Promise
Promise 是異步編程的一種解決方案,比傳統(tǒng)的解決方案——回調(diào)函數(shù)和事件——更合理且更強(qiáng)大。它最早由社區(qū)提出并實(shí)現(xiàn),ES6將其寫進(jìn)了語(yǔ)言標(biāo)準(zhǔn),統(tǒng)一了用法,并原生提供了Promise對(duì)象。
特點(diǎn)
- 對(duì)象的狀態(tài)不受外界影響 (3種狀態(tài))
- Pending狀態(tài)(進(jìn)行中)
- Fulfilled狀態(tài)(已成功)
- Rejected狀態(tài)(已失敗)
- 一旦狀態(tài)改變就不會(huì)再變 (兩種狀態(tài)改變:成功或失?。?
- Pending -> Fulfilled
- Pending -> Rejected
用法
創(chuàng)建Promise實(shí)例
var promise = new Promise(function(resolve, reject){
// ... some code
if (/* 異步操作成功 */) {
resolve(value);
} else {
reject(error);
}
})
??Promise構(gòu)造函數(shù)接受一個(gè)函數(shù)作為參數(shù),該函數(shù)的兩個(gè)參數(shù)分別是resolve和reject。它們是兩個(gè)函數(shù),由JavaScript引擎提供,不用自己部署。
??resolve作用是將Promise對(duì)象狀態(tài)由“未完成”變?yōu)椤俺晒Α保簿褪?code>Pending -> Fulfilled,在異步操作成功時(shí)調(diào)用,并將異步操作的結(jié)果作為參數(shù)傳遞出去;而reject函數(shù)則是將Promise對(duì)象狀態(tài)由“未完成”變?yōu)椤笆 保簿褪?code>Pending -> Rejected,在異步操作失敗時(shí)調(diào)用,并將異步操作的結(jié)果作為參數(shù)傳遞出去。
then
??Promise實(shí)例生成后,可用then方法分別指定兩種狀態(tài)回調(diào)參數(shù)。then 方法可以接受兩個(gè)回調(diào)函數(shù)作為參數(shù):
- Promise對(duì)象狀態(tài)改為Resolved時(shí)調(diào)用 (必選)
- Promise對(duì)象狀態(tài)改為Rejected時(shí)調(diào)用 (可選)
基本用法示例
function sleep(ms) {
return new Promise(function(resolve, reject) {
setTimeout(resolve, ms);
})
}
sleep(500).then( ()=> console.log("finished"));
??這段代碼定義了一個(gè)函數(shù)sleep,調(diào)用后,等待了指定參數(shù)(500)毫秒后執(zhí)行then中的函數(shù)。值得注意的是,Promise新建后就會(huì)立即執(zhí)行。
執(zhí)行順序
??接下來(lái)我們探究一下它的執(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新建后會(huì)立即執(zhí)行,所以首先輸出 AAA。然后,then方法指定的回調(diào)函數(shù)將在當(dāng)前腳本所有同步任務(wù)執(zhí)行完后才會(huì)執(zhí)行,所以BBB 最后輸出。
與定時(shí)器混用
??首先看一個(gè)實(shí)例:
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的順序不必再說(shuō),而2與3先輸出Promise的then,而后輸出定時(shí)器任務(wù)。原因則是Promise屬于JavaScript引擎內(nèi)部任務(wù),而setTimeout則是瀏覽器API,而引擎內(nèi)部任務(wù)優(yōu)先級(jí)高于瀏覽器API任務(wù),所以有此結(jié)果。
拓展 async/await
async
??顧名思義,異步。async函數(shù)對(duì) Generator 函數(shù)的改進(jìn),async 函數(shù)必定返回 Promise,我們把所有返回 Promise 的函數(shù)都可以認(rèn)為是異步函數(shù)。特點(diǎn)體現(xiàn)在以下四點(diǎn):
- 內(nèi)置執(zhí)行器
- 更好的語(yǔ)義
- 更廣的適用性
- 返回值是 Promise
await
??顧名思義,等待。正常情況下,await命令后面是一個(gè) Promise 對(duì)象,返回該對(duì)象的結(jié)果。如果不是 Promise 對(duì)象,就直接返回對(duì)應(yīng)的值。另一種情況是,await命令后面是一個(gè)thenable對(duì)象(即定義then方法的對(duì)象),那么await會(huì)將其等同于 Promise 對(duì)象。
混合使用
??先看示例:
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,返回一個(gè)Promise。然后在handle函數(shù)前加上async關(guān)鍵詞,這樣就定義了一個(gè)async函數(shù)。在該函數(shù)中,利用await來(lái)等待一個(gè)Promise。
Promise優(yōu)缺點(diǎn)
| 優(yōu)點(diǎn) | 缺點(diǎn) |
|---|---|
| 解決回調(diào) | 無(wú)法監(jiān)測(cè)進(jìn)行狀態(tài) |
| 鏈?zhǔn)秸{(diào)用 | 新建立即執(zhí)行且無(wú)法取消 |
| 減少嵌套 | 內(nèi)部錯(cuò)誤無(wú)法拋出 |