一、名字
? ? ? ? promise(首字母小寫):一個對象,Promise的實例對象
? ? ? ? Promise(首字母大寫,單數(shù)):Prmoise構(gòu)造函數(shù)
? ? ? ? Promises(首字母大寫,復(fù)數(shù)):指代Promise規(guī)范
二、Promises/A規(guī)范和ES6 Prmoises規(guī)范
? ? ? ? Prmoises規(guī)范有幾次升級,目前來說,Promises/A是最新的民間規(guī)范。ES6 Prmoises是最新的官方規(guī)范。
三、Promises的意義
? ? ? ? 1、解決回調(diào)金字塔的問題(回調(diào)圣誕樹,回調(diào)地獄)
? ? ? ? 2、可以同時管理成功回調(diào)和失敗回調(diào)
四、所謂“承諾”
? ? ? ? Promises這個單詞翻譯為“承諾”。程序的世界里,理解為:我承諾給你完成這些代碼的執(zhí)行。new有一個Prmoise實例,就是js引擎給你一個承諾。
? ? ? ? 執(zhí)行承諾,就會有成功或者失敗,只是概率問題。
? ? ? ? 在程序世界里,一個承諾也只會有三種狀態(tài):“未解決(pendding)”、“成功的(resolve)”、“失敗的(reject)”。
五、Promise構(gòu)造函數(shù)的能力
? ? ? ? 本質(zhì):prmoises寫法的本質(zhì)就是把 異步寫法擼成同步寫法。
? ? ? ? 怎么做到的呢?
????????就是安排一下代碼執(zhí)行的先后順序:Promise構(gòu)造函數(shù)有特殊的功能,傳入Prmoise構(gòu)造函數(shù)的函數(shù)參數(shù)會優(yōu)先第一執(zhí)行,也就是說,只要new一個Prmoise,那么Promise構(gòu)造函數(shù)的函數(shù)參數(shù)是最高優(yōu)先級執(zhí)行的,一直到new一個Promise對象實例后面的then()代碼才會執(zhí)行。鏈條行的每一個then()都會等到前面promise有了結(jié)果才會執(zhí)行。
? ? ? ? Promise是一個構(gòu)造函數(shù),用來生成prmoise實例。
? ? ? ? Promise構(gòu)造函數(shù)接受一個函數(shù)作為參數(shù),這個函數(shù)的兩個參數(shù)分別是:resolve和reject。他們是兩個函數(shù),有js引擎提供(自帶的。
? ? ? ? resolve函數(shù)的作用:將promise對象的狀態(tài)從“未完成”變成“成功”。在異步操作成功時調(diào)用,并將異步的結(jié)果作為參數(shù)傳遞出去。
? ? ? ? reject函數(shù)的通:將promise對象的狀態(tài)從“未完成”變成“失敗”。在異步操作失敗的時候調(diào)用,并將錯誤作為參數(shù)傳遞出去。
? ? ? ? promise對象生成以后,可以用then()方法分別制定resolve狀態(tài)和reject狀態(tài)的回到函數(shù)
六、擼代碼
? ? ? ? 傳統(tǒng)的回調(diào)地獄寫法:
? ? ? ? ? ? ? ? firstAsync(function(data){
? ? ? ? ? ? ? ? ? ? //拿到data的數(shù)據(jù) 處理業(yè)務(wù)邏輯 do something
? ? ? ? ? ? ? ? ? ? secondAsync(function(data2){
? ???????????????????????//拿到data2的數(shù)據(jù) 處理業(yè)務(wù)邏輯?do something
? ? ? ? ? ? ? ? ? ? ? ? thirdAsync(function(data3){
? ??????????????????????????????//拿到data3的數(shù)據(jù) 處理業(yè)務(wù)邏輯?do something
????????????????????????})
????????????????????})
????????????????})
? ? ? ?哈哈哈,像不像一個金字塔。可讀性和維護性都比較差
? ? ? ? 引入Promise的寫法:
? ??????firstAsync().then(function(data){
? ??????????????//拿到data的數(shù)據(jù) 處理業(yè)務(wù)邏輯 do something
? ? ? ? ? ? ? ? return?secondAsync() //繼續(xù)處理第二個異步
????????}).then(function(data2){
? ??????????//拿到data2的數(shù)據(jù) 處理業(yè)務(wù)邏輯 do something
? ? ? ? ? ? return?thirdAsync() //繼續(xù)處理第二個異步
????????}).then(function(data3){
? ??????????????//拿到data3的數(shù)據(jù) 處理業(yè)務(wù)邏輯 do something
????????})
? ? ? ? 通過then的鏈式寫法,把回調(diào)按照順序串聯(lián)起來。
? ? ? ? 更直接的例子:有做飯、吃飯、洗碗筷這三個異步的操作,他們是層層依賴,下一步的操作依賴上一步操作的結(jié)果
? ? ? ? =》
? ??????(1)下面通過樣例作為演示,我們定義做飯、吃飯、洗碗(cook、eat、wash)這三個方法,它們是層層依賴的關(guān)系,下一步的的操作需要使用上一部操作的結(jié)果。(這里使用?setTimeout?模擬異步操作)
? ? ????????????//做飯? ??
function cook(){
console.log("開始做飯");
var p = new Promise(function(resolve,reject){
setTimeout(function(){
console.log("做飯完畢")
resolve("老北京炸醬面")
},1000)
})
return p;
}
//吃飯
function eat(data){
console.log("開始吃飯:"+data)
var p = new Promise(function(resolve,reject){
setTimeout(function(){
console.log("吃飽啦")
resolve("筷子盤子碗")
},2000)
})
return p
}
//洗碗筷
function wash(data){
console.log("開始洗碗筷:"+data)
var p = new Promise(function(resolve,reject){
setTimeout(function(){
console.log("洗好啦")
resolve("干凈的碗筷")
},2000)
})
return p
}
(2)使用?then?鏈式調(diào)用這三個方法:
cook()
.then(function(data){
????returneat(data);
})
.then(function(data){
????returnwash(data);
})
.then(function(data){
????console.log(data);
});
好了,看運行的結(jié)果:
Promises.html:14 開始做飯
Promises.html:17 做飯完畢
Promises.html:26 開始吃飯:老北京炸醬面
Promises.html:29 吃飽啦
Promises.html:39 開始洗碗筷:筷子盤子碗
Promises.html:42 洗好啦
Promises.html:54 干凈的碗筷
七、all
? ? ? ? Promises的all方法,拓展了異步操作的能力,即在所有指定的異步操作都結(jié)束后才運行回調(diào)。
? ? ? ? 直接上代碼:
? ? ? ??//切菜
function cut(){
console.log("開始切菜:青菜")
var p = new Promise(function(resolve,reject){
setTimeout(function(){
console.log("切菜完畢")
resolve("切好的青菜")
},1000)
})
return p
}
//燒水
function boil(){
console.log("開始燒水")
var p = new Promise(function(resolve,reject){
setTimeout(function(){
console.log("燒水完畢")
resolve("燒好的水")
},2000)
})
return p
}
//all then把操作邏輯串起來
Promise.all([cut(),boil()]).then(function(data){
console.log("準備工作完畢")
console.log(data)
})
結(jié)果:
開始切菜:青菜
Promises.html:72 開始燒水
Promises.html:64 切菜完畢
Promises.html:76 燒水完畢
Promises.html:84 準備工作完畢
Promises.html:85 ["切好的青菜", "燒好的水"]
八、Promises的race方法:和all類似,是異步能力的拓展,區(qū)別是all是所有異步操作都結(jié)束才能執(zhí)行回調(diào),?race?的話只要有一個異步操作執(zhí)行完畢,就立刻執(zhí)行?then?回調(diào)。
注意:其它沒有執(zhí)行完畢的異步操作仍然會繼續(xù)執(zhí)行,而不是停止。
上面的切菜燒水操作定義好以后:
Promise.race([cut(),boil()]).then(function(data){
console.log("至少有一個工作準備好了")
console.log(data)
})
結(jié)果注意順序:
開始切菜:青菜
Promises.html:72 開始燒水
Promises.html:64 切菜完畢
Promises.html:89 至少有一個工作準備好了
Promises.html:90 切好的青菜
Promises.html:76 燒水完畢
注意,race的應(yīng)用場景很多,比如同時向后臺發(fā)起多個ajax的異步請求,并且都有超時時間設(shè)置。
比如:
//請求某個圖片資源
function requestImg(){
? ? var p = new Promise(function(resolve, reject){
? ? var img = new Image();
? ? img.onload = function(){
? ? ? resolve(img);
? ? }
? ? img.src = 'xxxxxx';
? ? });
? ? return p;
}
//延時函數(shù),用于給請求計時
function timeout(){
? ? var p = new Promise(function(resolve, reject){
? ? ? ? setTimeout(function(){
? ? ? ? ? ? reject('圖片請求超時');
? ? ? ? }, 5000);
? ? });
? ? return p;
}
Promise
.race([requestImg(), timeout()])
.then(function(results){
? ? console.log(results);
})
.catch(function(reason){
? ? console.log(reason);
});
上面代碼?requestImg?函數(shù)異步請求一張圖片,timeout?函數(shù)是一個延時?5?秒的異步操作。我們將它們一起放在?race?中賽跑。
如果?5?秒內(nèi)圖片請求成功那么便進入?then?方法,執(zhí)行正常的流程。
如果?5?秒鐘圖片還未成功返回,那么則進入?catch,報“圖片請求超時”的信息。