Promise
Promise 是異步編程的一種解決方案,比傳統(tǒng)的解決方案——回調(diào)函數(shù)和事件——更合理且更強大蝙茶。它最早由社區(qū)提出并實現(xiàn)扣唱,ES6將其寫進了語言標準,統(tǒng)一了用法唐瀑,并原生提供了Promise對象群凶。
特點
- 對象的狀態(tài)不受外界影響 (3種狀態(tài))
- Pending狀態(tài)(進行中)
- Fulfilled狀態(tài)(已成功)
- Rejected狀態(tài)(已失敗)
- 一旦狀態(tài)改變就不會再變 (兩種狀態(tài)改變:成功或失斀槿臁)
- Pending -> Fulfilled
- Pending -> Rejected
用法
創(chuàng)建Promise實例
var promise = new Promise(function(resolve, reject){
// ... some code
if (/* 異步操作成功 */) {
resolve(value);
} else {
reject(error);
}
})
??Promise構(gòu)造函數(shù)接受一個函數(shù)作為參數(shù)座掘,該函數(shù)的兩個參數(shù)分別是resolve
和reject
。它們是兩個函數(shù)柔滔,由JavaScript引擎提供溢陪,不用自己部署。
??resolve作用是將Promise對象狀態(tài)由“未完成”變?yōu)椤俺晒Α本龋簿褪?code>Pending -> Fulfilled形真,在異步操作成功時調(diào)用,并將異步操作的結(jié)果作為參數(shù)傳遞出去超全;而reject函數(shù)則是將Promise對象狀態(tài)由“未完成”變?yōu)椤笆 迸厮簿褪?code>Pending -> Rejected,在異步操作失敗時調(diào)用嘶朱,并將異步操作的結(jié)果作為參數(shù)傳遞出去蛾坯。
then
??Promise實例生成后,可用then
方法分別指定兩種狀態(tài)回調(diào)參數(shù)疏遏。then 方法可以接受兩個回調(diào)函數(shù)作為參數(shù):
- Promise對象狀態(tài)改為Resolved時調(diào)用 (必選)
- Promise對象狀態(tài)改為Rejected時調(diào)用 (可選)
基本用法示例
function sleep(ms) {
return new Promise(function(resolve, reject) {
setTimeout(resolve, ms);
})
}
sleep(500).then( ()=> console.log("finished"));
??這段代碼定義了一個函數(shù)sleep脉课,調(diào)用后,等待了指定參數(shù)(500)毫秒后執(zhí)行then中的函數(shù)财异。值得注意的是倘零,Promise新建后就會立即執(zhí)行。
執(zhí)行順序
??接下來我們探究一下它的執(zhí)行順序戳寸,看以下代碼:
let promise = new Promise(function(resolve, reject){
console.log("AAA");
resolve()
});
promise.then(() => console.log("BBB"));
console.log("CCC")
// AAA
// CCC
// BBB
??執(zhí)行后呈驶,我們發(fā)現(xiàn)輸出順序總是 AAA -> CCC -> BBB
。表明疫鹊,在Promise新建后會立即執(zhí)行袖瞻,所以首先輸出 AAA
。然后拆吆,then方法指定的回調(diào)函數(shù)將在當前腳本所有同步任務執(zhí)行完后才會執(zhí)行聋迎,所以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
??可以看到锈拨,結(jié)果輸出順序總是:1 -> 4 -> 3 -> 2
砌庄。1與4的順序不必再說,而2與3先輸出Promise的then,而后輸出定時器任務娄昆。原因則是Promise屬于JavaScript引擎內(nèi)部任務佩微,而setTimeout則是瀏覽器API,而引擎內(nèi)部任務優(yōu)先級高于瀏覽器API任務萌焰,所以有此結(jié)果哺眯。
拓展 async/await
async
??顧名思義,異步扒俯。async函數(shù)對 Generator 函數(shù)的改進奶卓,async 函數(shù)必定返回 Promise,我們把所有返回 Promise 的函數(shù)都可以認為是異步函數(shù)撼玄。特點體現(xiàn)在以下四點:
- 內(nèi)置執(zhí)行器
- 更好的語義
- 更廣的適用性
- 返回值是 Promise
await
??顧名思義夺姑,等待。正常情況下掌猛,await命令后面是一個 Promise 對象盏浙,返回該對象的結(jié)果。如果不是 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后)
??我們定義函數(shù)sleep,返回一個Promise孔飒。然后在handle函數(shù)前加上async關鍵詞灌闺,這樣就定義了一個async函數(shù)。在該函數(shù)中十偶,利用await來等待一個Promise菩鲜。
Promise優(yōu)缺點
優(yōu)點 | 缺點 |
---|---|
解決回調(diào) | 無法監(jiān)測進行狀態(tài) |
鏈式調(diào)用 | 新建立即執(zhí)行且無法取消 |
減少嵌套 | 內(nèi)部錯誤無法拋出 |