JS執行——Promise非同步程式設計
Promise
Promise 是非同步程式設計的一種解決方案,比傳統的解決方案——回撥函式和事件——更合理且更強大。它最早由社群提出並實現,ES6將其寫進了語言標準,統一了用法,並原生提供了Promise物件。
特點
- 物件的狀態不受外界影響 (3種狀態)
- Pending狀態(進行中)
- Fulfilled狀態(已成功)
- Rejected狀態(已失敗)
- 一旦狀態改變就不會再變 (兩種狀態改變:成功或失敗)
- Pending -> Fulfilled
- Pending -> Rejected
用法
建立Promise例項
var promise = new Promise(function(resolve, reject){
// ... some code
if (/* 非同步操作成功 */) {
resolve(value);
} else {
reject(error);
}
})
Promise建構函式接受一個函式作為引數,該函式的兩個引數分別是resolve
和reject
。它們是兩個函式,由JavaScript引擎提供,不用自己部署。
resolve作用是將Promise物件狀態由“未完成”變為“成功”,也就是Pending -> Fulfilled
,在非同步操作成功時呼叫,並將非同步操作的結果作為引數傳遞出去;而reject函式則是將Promise物件狀態由“未完成”變為“失敗”,也就是Pending -> Rejected
,在非同步操作失敗時呼叫,並將非同步操作的結果作為引數傳遞出去。
then
Promise例項生成後,可用then
方法分別指定兩種狀態回撥引數。then 方法可以接受兩個回撥函式作為引數:
- Promise物件狀態改為Resolved時呼叫 (必選)
- Promise物件狀態改為Rejected時呼叫 (可選)
基本用法示例
function sleep(ms) {
return new Promise(function(resolve, reject) {
setTimeout(resolve, ms);
})
}
sleep(500).then( ()=> console.log("finished"));
這段程式碼定義了一個函式sleep,呼叫後,等待了指定引數(500)毫秒後執行then中的函式。值得注意的是,Promise新建後就會立即執行。
執行順序
接下來我們探究一下它的執行順序,看以下程式碼:
let promise = new Promise(function(resolve, reject){
console.log("AAA");
resolve()
});
promise.then(() => console.log("BBB"));
console.log("CCC")
// AAA
// CCC
// BBB
執行後,我們發現輸出順序總是 AAA -> CCC -> BBB
。表明,在Promise新建後會立即執行,所以首先輸出 AAA
。然後,then方法指定的回撥函式將在當前指令碼所有同步任務執行完後才會執行,所以BBB 最後輸出
。
與定時器混用
首先看一個例項:
let promise = new Promise(function(resolve, reject){
console.log("1");
resolve();
});
setTimeout(()=>console.log("2"), 0);
promise.then(() => console.log("3"));
console.log("4");
// 1
// 4
// 3
// 2
可以看到,結果輸出順序總是:1 -> 4 -> 3 -> 2
。1與4的順序不必再說,而2與3先輸出Promise的then,而後輸出定時器任務。原因則是Promise屬於JavaScript引擎內部任務,而setTimeout則是瀏覽器API,而引擎內部任務優先順序高於瀏覽器API任務,所以有此結果。
拓展 async/await
async
顧名思義,非同步。async函式對 Generator 函式的改進,async 函式必定返回 Promise,我們把所有返回 Promise 的函式都可以認為是非同步函式。特點體現在以下四點:
- 內建執行器
- 更好的語義
- 更廣的適用性
- 返回值是 Promise
await
顧名思義,等待。正常情況下,await命令後面是一個 Promise 物件,返回該物件的結果。如果不是 Promise 物件,就直接返回對應的值。另一種情況是,await命令後面是一個thenable物件(即定義then方法的物件),那麼await會將其等同於 Promise 物件。
混合使用
先看示例:
function sleep(ms) {
return new Promise(function(resolve, reject) {
setTimeout(resolve,ms);
})
}
async function handle(){
console.log("AAA")
await sleep(5000)
console.log("BBB")
}
handle();
// AAA
// BBB (5000ms後)
我們定義函式sleep,返回一個Promise。然後在handle函式前加上async關鍵詞,這樣就定義了一個async函式。在該函式中,利用await來等待一個Promise。
Promise優缺點
優點 | 缺點 |
---|---|
解決回撥 | 無法監測進行狀態 |
鏈式呼叫 | 新建立即執行且無法取消 |
減少巢狀 | 內部錯誤無法丟擲 |
連結:https://www.jianshu.com/p/b16e7c9e1f9f