目錄
- 簡介
- 用法
- 輸出
- 語法
- 字面量
- 變數
- 運算子
- 陳述句
- 關鍵字
- 注釋
- 資料型別
- 函式
- 函式運算式
- Function() 建構式
- 自呼叫函式
- 箭頭函式
- arguments 物件
- 使用建構式呼叫函式
- 作為函式方法呼叫函式
- 閉包
- 物件
- 物件定義
- 物件屬性
- 物件方法
- 作用域
- 區域作用域
- 全域變數
- 變數生命周期
- HTML 中的全域變數
- 事件
- HTML 事件
- 常見的HTML事件
- typeof, null, 和 undefined
- typeof 運算子
- null
- undefined
- undefined 和 null 的區別
- 型別轉換
- 資料型別
- typeof 運算子
- constructor 屬性
- JavaScript 型別轉換
- 正則運算式
- 語法
- 使用字串方法
- 使用 RegExp 物件
- 表單
- 表單驗證
- this 的多種指向:
- let 和 const
- let關鍵字
- 塊級作用域(Block Scope)
- 重新定義變數
- 使用全域變數
- 重置變數
- const 關鍵字
- 重置變數
- let關鍵字
- JSON
- 語法規則
- JSON 字串和 JavaScript 物件互轉
- void(0) 含義
- 包含了一個位置資訊,默認的錨是#top 也就是網頁的上端,
- 異步編程
- 異步的概念
- 什么時候用異步編程
- 回呼函式
- 異步 AJAX
- Promise
- 構造 Promise
- Promise 的使用
- Promise 函式
- 異步函式
簡介
直接寫入 HTML 輸出流:
document.write("<h1>這是一個標題</h1>");
document.write("<p>這是一個段落,</p>");
注:只能在 HTML 輸出中使用 document.write,如果在檔案加載后使用該方法,會覆寫整個檔案,
對事件的反應:
<button type="button" onclick="alert('歡迎!')">點我!</button>
注:alert() 函式對于代碼測驗非常方便,onclick 事件只是眾多事件之一,
改變 HTML 內容:
x=document.getElementById("demo"); //查找元素
x.innerHTML="Hello JavaScript"; //改變內容
注:document.getElementById("some id")這個方法是 HTML DOM 中定義的,DOM (Document Object Model)(檔案物件模型)是用于訪問 HTML 元素的正式 W3C 標準,
改變 HTML 影像:
動態地改變 HTML <image> 的來源(src):
<script>
function changeImage()
{
var s = document.getElementById('myimage');
s.src = https://www.cnblogs.com/timefiles/p/s.src.match('bulboff')?"/images/pic_bulbon.gif":"/images/pic_bulboff.gif";
}
</script>
<img loading="lazy" id="myimage" onclick="changeImage()" src="https://img.uj5u.com/2021/06/21/245585210618321.gif" width="100" height="180">
改變 HTML 樣式:
x=document.getElementById("demo") //找到元素
x.style.color="#ff0000"; //改變樣式
驗證輸入:
if isNaN(x) { alert("不是數字"); }
用法
標簽:在 HTML 頁面中插入 JavaScript,請使用 <script> 標簽,
外部的 JavaScript:外部檔案通常包含被多個網頁使用的代碼,檔案擴展名是 .js,請在 <script> 標簽的 "src" 屬性中設定該 .js 檔案,
可以在 HTML 檔案中放入不限數量的腳本,腳本可位于 HTML 的 <body> 或 <head> 部分中,或者同時存在于兩個部分中,
通常的做法是把函式放入 部分中,或者放在頁面底部,
輸出
JavaScript 可以通過不同的方式來輸出資料:
- 使用 window.alert() 彈出警告框,
- 使用 document.write() 方法將內容寫到 HTML 檔案中,
- 使用 innerHTML 寫入到 HTML 元素,
- 使用 console.log() 寫入到瀏覽器的控制臺,
語法
JavaScript 是一個腳本語言,輕量級,但功能強大的編程語言,
字面量
在編程語言中,一般固定值稱為字面量,如 3.14,
- 數字(Number)字面量 可以是整數或者是小數,或者是科學計數(e),如 123e5 ,
- 字串(String)字面量 可以使用單引號或雙引號:
"John Doe"
'John Doe'
-
運算式字面量 用于計算,如5 + 6 、5 * 10 ,
-
陣列(Array)字面量 定義一個陣列:
[40, 100, 1, 5, 25, 10] ,
- 物件(Object)字面量 定義一個物件:
{firstName:"John", lastName:"Doe", age:50, eyeColor:"blue"}
- 函式(Function)字面量 定義一個函式:
function myFunction(a, b) { return a * b;}
變數
JavaScript 使用關鍵字 var 來定義變數, 使用等號來為變數賦值:
var x, length;
x = 5;
length = 6;
注:變數是一個名稱,字面量是一個值,變數通常是可變的,字面量是一個恒定的值,
運算子
JavaScript語言有多種型別的運算子:
| 型別 | 實體 | 描述 |
|---|---|---|
| 賦值,算術和位運算子 | = + - * / | 在 JS 運算子中描述 |
| 條件,比較及邏輯運算子 | == != < > | 在 JS 比較運算子中描述 |
陳述句
在 HTML 中,JavaScript 陳述句向瀏覽器發出的命令,陳述句是用分號分隔:
x = 5 + 6;
y = x * 10;
關鍵字
JavaScript 關鍵字用于標識要執行的操作,和其他任何編程語言一樣,JavaScript 保留了一些關鍵字為自己所用,
注:基本上,編程通用的關鍵字盡量不要使用即可,
注釋
不是所有的 JavaScript 陳述句都是"命令",注釋后的內容將會被瀏覽器忽略,
單行注釋以 // 開頭,多行注釋以 /* 開始,以 */ 結尾,
資料型別
JavaScript 有多種資料型別:數字,字串,陣列,物件等等:
var length = 16; // Number 通過數字字面量賦值
var points = x * 10; // Number 通過運算式字面量賦值
var lastName = "Johnson"; // String 通過字串字面量賦值
var cars = ["Saab", "Volvo", "BMW"]; // Array 通過陣列字面量賦值
var person = {firstName:"John", lastName:"Doe"}; // Object 通過物件字面量賦值
函式
JavaScript 陳述句可以寫在函式內,函式可以重復參考,參考一個函式 = 呼叫函式(執行函式內的陳述句):
function myFunction(a, b) {
return a * b; // 回傳 a 乘以 b 的結果
}
注:JavaScript 對大小寫是敏感的,使用 Unicode 字符集,
函式運算式
JavaScript 函式可以通過一個運算式定義:
var x = function (a, b) {return a * b};
var z = x(4, 3);
以上函式實際上是一個 匿名函式 (函式沒有名稱),函式存盤在變數中,不需要函式名稱,通常通過變數名來呼叫,
Function() 建構式
函式可以通過內置的 JavaScript 函式構造器(Function())定義:
var myFunction = new Function("a", "b", "return a * b");
var x = myFunction(4, 3);
注:在 JavaScript 中,需要避免使用 new 關鍵字,建議使用函式運算式替換函式構造器(Function()),
自呼叫函式
函式運算式可以 "自呼叫",自呼叫運算式會自動呼叫,如果運算式后面緊跟 () ,則會自動呼叫:
(function () {
var x = "Hello!!"; // 我將呼叫自己
})();
箭頭函式
箭頭函式運算式的語法比普通函式運算式更簡潔:
(引數1, 引數2, …, 引數N) => { 函式宣告 }
(引數1, 引數2, …, 引數N) => 運算式(單一)
// 相當于:(引數1, 引數2, …, 引數N) =>{ return 運算式; }
(單一引數) => {函式宣告}
單一引數 => {函式宣告}
() => {函式宣告}
// ES5
var x = function(x, y) {
return x * y;
}
// ES6
const x = (x, y) => x * y;
注:當使用箭頭函式的時候,箭頭函式會默認系結外層 this 的值,所以在箭頭函式中 this 的值和外層的 this 是一樣的,
arguments 物件
JavaScript 函式有個內置的物件 arguments 物件,argument 物件包含了函式呼叫的引數陣列,
創建一個函式用來統計所有數值的和:
x = sumAll(1, 123, 500, 115, 44, 88);
function sumAll() {
var i, sum = 0;
for (i = 0; i < arguments.length; i++) {
sum += arguments[i];
}
return sum;
}
使用建構式呼叫函式
如果函式呼叫前使用了 new 關鍵字, 則是呼叫了建構式:
// 建構式:
function myFunction(arg1, arg2) {
this.firstName = arg1;
this.lastName = arg2;
}
// This creates a new object
var x = new myFunction("John","Doe");
x.firstName; // 回傳 "John"
注:建構式中 this 關鍵字沒有任何的值,this 的值在函式呼叫實體化物件(new object)時創建,
作為函式方法呼叫函式
在 JavaScript 中, 函式是物件,有它的屬性和方法,
call() 和 apply() 是預定義的函式方法, 兩個方法可用于呼叫函式,兩個方法的第一個引數必須是物件本身:
function myFunction(a, b) {
return a * b;
}
myObject = myFunction.call(myObject, 10, 2); // 回傳 20
myArray = [10, 2];
myObject = myFunction.apply(myObject, myArray); // 回傳 20
call() 和 apply()兩者的區別在于第二個引數: apply傳入的是一個引數陣列,也就是將多個引陣列合成為一個陣列傳入,而call則作為call的引數傳入(從第二個引數開始),
注:通過 call() 或 apply() 方法可以設定 this 的值, 且作為已存在物件的新方法呼叫,
閉包
參考函式自我呼叫:
var add = (function () {
var counter = 0;
return function () {return counter += 1;}
})();
add();
add();
add();
// 計數器為 3
變數 add 指定了函式自我呼叫的回傳字值,自我呼叫函式只執行一次,設定計數器為 0,并回傳函式運算式,
add變數可以作為一個函式使用,它可以訪問函式上一層作用域的計數器,這個叫作 JavaScript 閉包,
它使得函式擁有私有變數變成可能,計數器受匿名函式的作用域保護,只能通過 add 方法修改,
注:閉包是一種保護私有變數的機制,在函式執行時形成私有的作用域,保護里面的私有變數不受外界干擾,形成一個不銷毀的堆疊環境,
物件
JavaScript 物件是擁有屬性和方法的資料,
物件定義
定義和創建 JavaScript 物件:
var person = {
//屬性
firstName: "John",
lastName : "Doe",
id : 5566,
//方法
fullName : function()
{
return this.firstName + " " + this.lastName;
}
物件屬性
可以說 "JavaScript 物件是變數的容器",或者說"JavaScript 物件是鍵值對的容器",
鍵值對通常寫法為 name : value (鍵與值以冒號分割),鍵值對在 JavaScript 物件通常稱為 物件屬性,
可以通過兩種方式訪問物件屬性:
//方法1
person.lastName;
//方法2
person["lastName"];
物件方法
物件的方法定義了一個函式,并作為物件的屬性存盤,
物件方法通過添加 () 呼叫 (作為一個函式):
name = person.fullName();
如果把函式當成屬性訪問(不添加()),它將作為一個定義函式的字串回傳:
name = person.fullName;
作用域
在 JavaScript 中, 作用域為可訪問變數,物件,函式的集合,
區域作用域
變數在函式內宣告,變數為區域作用域,只能在函式內部訪問:
// 此處不能呼叫 carName 變數
function myFunction() {
var carName = "Volvo";
// 函式內可呼叫 carName 變數
}
不同的函式可以使用相同名稱的變數,區域變數在函式開始執行時創建,函式執行完后區域變數會自動銷毀,
注:函式引數只在函式內起作用,是區域變數,
全局變數
變數在函式外定義,即為全域變數,全域變數有全域作用域—— 網頁中所有腳本和函式均可使用:
var carName = " Volvo";
// 此處可呼叫 carName 變數
function myFunction() {
// 函式內可呼叫 carName 變數
}
如果變數在函式內沒有宣告(沒有使用 var 關鍵字),該變數為全域變數:
// 此處可呼叫 carName 變數
function myFunction() {
carName = "Volvo";
// 此處可呼叫 carName 變數
}
變數生命周期
JavaScript 變數生命周期在它宣告時初始化,區域變數在函式執行完畢后銷毀,全域變數在頁面關閉后銷毀,
HTML 中的全域變數
在 HTML 中, 全域變數是 window 物件:所有資料變數都屬于 window 物件,
//此處可使用 window.carName
function myFunction() {
carName = "Volvo";
}
事件
HTML 事件是發生在 HTML 元素上的事情, JavaScript 可以觸發這些事件,
HTML 事件
HTML 事件可以是瀏覽器行為,也可以是用戶行為,以下是 HTML 事件的實體:
- HTML 頁面完成加載
- HTML input 欄位改變時
- HTML 按鈕被點擊
HTML 元素中可以添加事件屬性,使用 JavaScript 代碼來添加 HTML 元素:
<!-- 單引號 -->
<some-HTML-element some-event='JavaScript 代碼'>
<!-- 雙引號 -->
<some-HTML-element some-event="JavaScript 代碼">
常見的HTML事件
下面是一些常見的HTML事件的串列:
| 事件 | 描述 |
|---|---|
| onchange | HTML 元素改變 |
| onclick | 用戶點擊 HTML 元素 |
| onmouseover | 用戶在一個HTML元素上移動滑鼠 |
| onmouseout | 用戶從一個HTML元素上移開滑鼠 |
| onkeydown | 用戶按下鍵盤按鍵 |
| onload | 瀏覽器已完成頁面的加載 |
更多事件串列: JavaScript 參考手冊 - HTML DOM 事件
typeof, null, 和 undefined
typeof 運算子
可以使用 typeof 運算子來檢測變數的資料型別:
typeof "John" // 回傳 string
typeof 3.14 // 回傳 number
typeof false // 回傳 boolean
typeof [1,2,3,4] // 回傳 object
typeof {name:'John', age:34} // 回傳 object
*注:在JavaScript中,陣列是一種特殊的物件型別,因此 typeof [1,2,3,4] 回傳 object, *
null
null是一個只有一個值的特殊型別,表示一個空物件參考(用 typeof 檢測 null 回傳是object),可以設定為 null 來清空物件:
var person = null; // 值為 null(空), 但型別為物件
也可以設定為 undefined 來清空物件:
var person = undefined; // 值為 undefined, 型別為 undefined
undefined
在 JavaScript 中, undefined 是一個沒有設定值的變數,typeof 一個沒有值的變數會回傳 undefined:
var person; // 值為 undefined(空), 型別是undefined
任何變數都可以通過設定值為 undefined 來清空, 型別為 undefined:
person = undefined; // 值為 undefined, 型別是undefined
undefined 和 null 的區別
null 和 undefined 的值相等,但型別不等:
typeof undefined // undefined
typeof null // object
null === undefined // false
null == undefined // true
型別轉換
資料型別
在 JavaScript 中有 6 種不同的資料型別:
- string
- number
- boolean
- object
- function
- symbol
3 種物件型別:
- Object
- Date
- Array
2 個不包含任何值的資料型別:
- null
- undefined
typeof 運算子
可以使用 typeof 運算子來查看 JavaScript 變數的資料型別:
typeof "John" // 回傳 string
typeof 3.14 // 回傳 number
typeof NaN // 回傳 number
typeof false // 回傳 boolean
typeof [1,2,3,4] // 回傳 object
typeof {name:'John', age:34} // 回傳 object
typeof new Date() // 回傳 object
typeof function () {} // 回傳 function
typeof myCar // 回傳 undefined (如果 myCar 沒有宣告)
typeof null // 回傳 object
constructor 屬性
constructor 屬性回傳所有 JavaScript 變數的建構式:
"John".constructor // 回傳函式 String() { [native code] }
(3.14).constructor // 回傳函式 Number() { [native code] }
false.constructor // 回傳函式 Boolean() { [native code] }
[1,2,3,4].constructor // 回傳函式 Array() { [native code] }
{name:'John', age:34}.constructor // 回傳函式 Object() { [native code] }
new Date().constructor // 回傳函式 Date() { [native code] }
function () {}.constructor // 回傳函式 Function(){ [native code] }
可以使用 constructor 屬性來查看物件是否為陣列 (包含字串 "Array")、日期 (包含字串 "Date"):
function isArray(myArray) {
return myArray.constructor.toString().indexOf("Array") > -1;
}
function isDate(myDate) {
return myDate.constructor.toString().indexOf("Date") > -1;
}
JavaScript 型別轉換
- 全域方法 String():可以將數字、字母、變數、運算式、布林值、日期轉換為字串
- Number 方法 toString():可以將數字轉換為字串,
- Boolean 方法 toString():可以將布林值轉換為字串,"false"、"true",
- Date 方法 toString():可以將日期物件轉換為字串,回傳 “Thu Jul 17 2014 15:38:19 GMT+0200 (W. Europe Daylight Time)”,
- 全域方法 Number():可以將字串、布林值、日期轉換為數字,空字串轉換為 0,其他的字串會轉換為 NaN (不是個數字),布林值對應0和1,日期回傳 1404568027739(毫秒數),
- 一元運算子 +:Operator + 可用于將變數轉換為數字,如果變數不能轉換,則值為 NaN (不是一個數字),
- **日期方法 getTime() **:可將日期轉換為數字,回傳 1404568027739(毫秒數),
正則運算式
語法
/正則運算式主體/修飾符(可選)
其中修飾符是可選的:
var patt = /runoob/i
- /runoob/i 是一個正則運算式,
- runoob 是一個正則運算式主體 (用于檢索),
- i 是一個修飾符 (搜索不區分大小寫),
使用字串方法
在 JavaScript 中,正則運算式通常用于兩個字串方法 : search() 和 replace(),
- search() 方法:用于檢索字串中指定的子字串,或檢索與正則運算式相匹配的子字串,并回傳子串的起始位置,
var str = "Visit Runoob!";
var n = str.search(/Runoob/i); //不區分大小
var n = str.search("Runoob");
- replace() 方法:用于在字串中用一些字符替換另一些字符,或替換一個與正則運算式匹配的子串,
var str = document.getElementById("demo").innerHTML;
var txt = str.replace(/microsoft/i,"Runoob"); //不區分大小
var txt = str.replace("Microsoft","Runoob");
使用 RegExp 物件
在 JavaScript 中,RegExp 物件是一個預定義了屬性和方法的正則運算式物件,
- test() 方法:用于檢測一個字串是否匹配某個模式,如果字串中含有匹配的文本,則回傳 true,否則回傳 false,
var patt = /e/;
patt.test("The best things in life are free!");
//以上兩行代碼可以合并為一行:
/e/.test("The best things in life are free!");
- **exec() 方法:用于檢索字串中的正則運算式的匹配,該函式回傳一個存放匹配結果的陣列,未找到匹配則回傳值為 null,
/e/.exec("The best things in life are free!");
參考 JavaScript RegExp 參考手冊,
表單
表單驗證
判斷表單欄位(fname)值是否存在, 如果不存在,就彈出資訊,阻止表單提交:
function validateForm() {
var x = document.forms["myForm"]["fname"].value;
if (x == null || x == "") {
alert("需要輸入名字,");
return false;
}
}
<form name="myForm" action="demo_form.php" onsubmit="return validateForm()" method="post">
名字: <input type="text" name="fname">
<input type="submit" value="https://www.cnblogs.com/timefiles/p/提交">
</form>
多表單使用同一驗證函式可以使用以下方法:
function validateForm(form) {
var x = form.name.value;
if (x == null || x == "") {
alert("輸入不能為空!");
return false;
}
}
所有表單呼叫時都使用:
onsubmit="return validateForm(this)"
onsubmit="validateForm()" 能夠呼叫 validateForm() 對表單進行驗證,但是在驗證不通過的情況下,并不能阻止表單提交,
onsubmit="return validateForm()" 當驗證不通過時,回傳 false,可以阻止表單提交,
onsubmit="return validateForm()" 相當于復寫了 onsubmit 的默認方法(默認回傳 true),根據 validateForm() 的結果回傳 true 或 false,當驗證不通過時,回傳 false,onsubmit="return false;" 阻止表單提交,
this 的多種指向:
- 在物件方法中, this 指向呼叫它所在方法的物件,
- 單獨使用 this,它指向全域(Global)物件,
- 函式使用中,this 指向函式的所屬者,
- 嚴格模式下函式是沒有系結到 this 上,這時候 this 是 undefined,
- 在 HTML 事件句柄中,this 指向了接收事件的 HTML 元素,
- apply 和 call 允許切換函式執行的背景關系環境(context),即 this 系結的物件,可以將 this 參考到任何物件,
let 和 const
let關鍵字
塊級作用域(Block Scope)
使用 var 關鍵字宣告的變數不具備塊級作用域的特性,它在 {} 外依然能被訪問到:
{
var x = 2;
}
// 這里可以使用 x 變數
let 宣告的變數只在 let 命令所在的代碼塊 {} 內有效,在 {} 之外不能訪問:
{
let x = 2;
}
// 這里不能使用 x 變數
重新定義變數
使用 var 關鍵字重新宣告變數可能會帶來問題,在塊中重新宣告變數也會重新宣告塊外的變數:
var x = 10;
// 這里輸出 x 為 10
{
var x = 2;
// 這里輸出 x 為 2
}
// 這里輸出 x 為 2
let 關鍵字可以解決這個問題,它只在 let 命令所在的代碼塊 {} 內有效:
var x = 10;
// 這里輸出 x 為 10
{
let x = 2;
// 這里輸出 x 為 2
}
// 這里輸出 x 為 10
使用全域變數
使用 var 關鍵字宣告的全域作用域變數屬于 window 物件:
var carName = "Volvo";
// 可以使用 window.carName 訪問變數
使用 let 關鍵字宣告的全域作用域變數不屬于 window 物件:
let carName = "Volvo";
// 不能使用 window.carName 訪問變數
重置變數
- 使用 var 關鍵字宣告的變數在任何地方都可以修改
- 在相同的作用域或塊級作用域中,不能使用 let 關鍵字來重置 var 關鍵字宣告的變數
- 在相同的作用域或塊級作用域中,不能使用 let 關鍵字來重置 let 關鍵字宣告的變數
- 在相同的作用域或塊級作用域中,不能使用 var 關鍵字來重置 let 關鍵字宣告的變數
- let 關鍵字在不同作用域,或不同塊級作用域中是可以重新宣告賦值的
const 關鍵字
const 用于宣告一個或多個常量,宣告時必須進行初始化,且初始化后值不可再修改,
const定義常量與使用let 定義的變數相似:
- 二者都是塊級作用域
- 都不能和它所在作用域內的其他變數或函式擁有相同的名稱
兩者還有以下兩點區別:
- const宣告的常量必須初始化,而let宣告的變數不用
- const 定義常量的值不能通過再賦值修改,也不能再次宣告,而 let 定義的變數值可以修改,
注:const 定義的變數并非不可改變,比如使用const宣告物件,可以改變物件值,可以使用Object.freeze()方法來 凍結變數 ,被凍結后的物件只能進行讀操作,
重置變數
- 使用 var 關鍵字宣告的變數在任何地方都可以修改
- 在相同的作用域或塊級作用域中,不能使用 const 關鍵字來重置 var 和 let關鍵字宣告的變數
- 在相同的作用域或塊級作用域中,不能使用 const 關鍵字來重置 const 關鍵字宣告的變數
- const 關鍵字在不同作用域,或不同塊級作用域中是可以重新宣告賦值的
JSON
JSON 是用于存盤和傳輸資料的格式,通常用于服務端向網頁傳遞資料 ,
語法規則
- 資料為 鍵/值 對
- 資料由逗號分隔
- 大括號保存物件
- 方括號保存陣列
{"sites":[
{"name":"Runoob", "url":"www.runoob.com"},
{"name":"Google", "url":"www.google.com"},
{"name":"Taobao", "url":"www.taobao.com"}
]}
JSON 字串和 JavaScript 物件互轉
要實作從JSON字串轉換為JS物件,使用 JSON.parse() 方法:
var obj = JSON.parse('{"a": "Hello", "b": "World"}'); //結果是 {a: 'Hello', b: 'World'} 一個物件
要實作從JS物件轉換為JSON字串,使用 JSON.stringify() 方法:
var json = JSON.stringify({a: 'Hello', b: 'World'}); //結果是 '{"a": "Hello", "b": "World"}' 一個JSON格式的字串
void(0) 含義
javascript:void(0) 中最關鍵的是 void 關鍵字, void 是 JavaScript 中非常重要的關鍵字,該運算子指定要計算一個運算式但是不回傳值,
void(alert("Warnning!"))
href="https://www.cnblogs.com/timefiles/p/#"與href="javascript:void(0)"的區別:
-
包含了一個位置資訊,默認的錨是#top 也就是網頁的上端,
- javascript:void(0), 僅僅表示一個死鏈接,
在頁面很長的時候會使用 # 來定位頁面的具體位置,格式為:# + id,如果要定義一個死鏈接請使用 javascript:void(0):
<a href="javascript:void(0);">點我沒有反應的!</a>
<a href="https://www.cnblogs.com/timefiles/p/#pos">點我定位到指定位置!</a>
<br>
...
<br>
<p id="pos">尾部定位點</p>
異步編程
異步的概念
異步(Asynchronous, async)是與同步(Synchronous, sync)相對的概念,同步按碼順序執行,異步不按照代碼順序執行,異步的執行效率更高,
通俗地解釋一下異步:異步就是從主執行緒發射一個子執行緒來完成任務,
什么時候用異步編程
主執行緒作為一個執行緒,不能夠同時接受多方面的請求,當一個事件沒有結束時,界面將無法處理其他請求,
現在有一個按鈕,如果設定它的 onclick 事件為一個死回圈,那么當這個按鈕按下,整個網頁將失去回應,
子執行緒有一個局限:一旦發射了以后就會與主執行緒失去同步,無法確定它的結束,
為了解決這個問題,JavaScript 中的異步操作函式往往通過回呼函式來實作異步任務的結果處理,
回呼函式
回呼函式就是一個函式,在啟動一個異步任務的時候就告訴它:等完成了這個任務之后要干什么,
function print() {
document.getElementById("demo").innerHTML="RUNOOB!";
}
setTimeout(print, 3000);
這段程式中的 setTimeout 就是一個消耗時間較長(3 秒)的程序,它的第一個引數是個回呼函式,第二個引數是毫秒數,這個函式執行之后會產生一個子執行緒,子執行緒會等待 3 秒,然后執行回呼函式 "print",在命令列輸出 "Time out",
不必單獨定義一個函式 print ,常常將上面的程式寫成:
setTimeout(function () {
document.getElementById("demo").innerHTML="RUNOOB!";
}, 3000);
異步 AJAX
除了 setTimeout 函式以外,異步回呼廣泛應用于 AJAX 編程,參考:https://www.runoob.com/ajax/ajax-tutorial.html
XMLHttpRequest 常常用于請求來自遠程服務器上的 XML 或 JSON 資料,一個標準的 XMLHttpRequest 物件往往包含多個回呼:
var xhr = new XMLHttpRequest();
xhr.onload = function () {
// 輸出接收到的文字資料
document.getElementById("demo").innerHTML=xhr.responseText;
}
xhr.onerror = function () {
document.getElementById("demo").innerHTML="請求出錯";
}
// 發送異步 GET 請求
xhr.open("GET", "https://www.runoob.com/try/ajax/ajax_info.txt", true);
xhr.send();
XMLHttpRequest 的 onload 和 one rror 屬性都是函式,分別在它請求成功和請求失敗時被呼叫,
如果使用完整的 jQuery 庫,也可以更加優雅的使用異步 AJAX:
$.get("https://www.runoob.com/try/ajax/demo_test.php",function(data,status){
alert("資料: " + data + "\n狀態: " + status);
});
Promise
Promise 是一個 ECMAScript 6 提供的類,目的是更加優雅地書寫復雜的異步任務,由于 Promise 是 ES6 新增加的,一些舊的瀏覽器并不支持,
構造 Promise
現在新建一個 Promise 物件:
new Promise(function (resolve, reject) {
// 要做的事情...
});
用 Promise 來實作三次輸出字串,第一次間隔 1 秒,第二次間隔 4 秒,第三次間隔 3 秒:
new Promise(function (resolve, reject) {
setTimeout(function () {
console.log("First");
resolve();
}, 1000);
}).then(function () {
return new Promise(function (resolve, reject) {
setTimeout(function () {
console.log("Second");
resolve();
}, 4000);
});
}).then(function () {
setTimeout(function () {
console.log("Third");
}, 3000);
});
Promise 的使用
下面通過剖析這段 Promise "計時器" 代碼來講述 Promise 的使用:
Promise 建構式只有一個引數,是一個函式,這個函式在構造之后會直接被異步運行——稱之為起始函式,
**起始函式包含兩個引數 resolve 和 reject*8,當 Promise 被構造時起始函式會被異步執行:
new Promise(function (resolve, reject) {
console.log("Run");
});
resolve 和 reject 都是函式,其中呼叫 resolve 代表一切正常,reject 是出現例外時所呼叫的:
new Promise(function (resolve, reject) {
var a = 0;
var b = 1;
if (b == 0) reject("Divide zero");
else resolve(a / b);
}).then(function (value) {
console.log("a / b = " + value);
}).catch(function (err) {
console.log(err);
}).finally(function () {
console.log("End");
});
Promise 類有 .then() .catch() 和 .finally() 三個方法,這三個方法的引數都是一個函式:
- .then() 可以將引數中的函式添加到當前 Promise 的正常執行序列;
- .catch() 則是設定 Promise 的例外處理序列;
- .finally() 是在 Promise 執行的最后一定會執行的序列,
.then() 傳入的函式會按順序依次執行,有任何例外都會直接跳到 catch 序列:
new Promise(function (resolve, reject) {
console.log(1111);
resolve(2222);
}).then(function (value) {
console.log(value);
return 3333;
}).then(function (value) {
console.log(value);
throw "An error";
}).catch(function (err) {
console.log(err);
});
執行結果:
1111
2222
3333
An error
- resolve() 中可以放置一個引數用于向下一個 then 傳遞一個值,then 中的函式也可以回傳一個值傳遞給 then,如果 then 中回傳的是一個 Promise 物件,那么下一個 then 將相當于對這個回傳的 Promise 進行操作,
- reject() 引數中一般會傳遞一個例外給之后的 catch 函式用于處理例外,
- **resolve 和 reject 的作用域只有起始函式,不包括 then 以及其他序列,
- **resolve 和 reject 并不能夠使起始函式停止運行,別忘了 return,
Promise 函式
可以將上面程式的核心部分寫成一個 Promise 函式:
function print(delay, message) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
console.log(message);
resolve();
}, delay);
});
}
然后實作程式功能:
print(1000, "First").then(function () {
return print(4000, "Second");
}).then(function () {
print(3000, "Third");
});
異步函式
異步函式(async function)是 ECMAScript 2017 (ECMA-262) 標準的規范,可以上面實作程式功能的代碼變得更好看:
async function asyncFunc() {
await print(1000, "First");
await print(4000, "Second");
await print(3000, "Third");
}
asyncFunc();
異步函式 async function 中可以使用 await 指令,await 指令后必須跟著一個 Promise,異步函式會在這個 Promise 運行中暫停,直到其運行結束再繼續運行,
異步函式實際上原理與 Promise 原生 API 的機制是一模一樣的,處理例外的機制將用 try-catch 塊實作:
async function asyncFunc() {
try {
await new Promise(function (resolve, reject) {
throw "Some error"; // 或者 reject("Some error")
});
} catch (err) {
console.log(err);
// 會輸出 Some error
}
}
asyncFunc();
如果 Promise 有一個正常的回傳值,await 陳述句也會回傳它:
async function asyncFunc() {
let value = https://www.cnblogs.com/timefiles/p/await new Promise(
function (resolve, reject) {
resolve("Return value");
}
);
console.log(value);
}
asyncFunc();
輸出:
Return value
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/288219.html
標籤:JavaScript
下一篇:[測驗]Sprint Boot
