JS中Promise函數(shù)then的奧秘探究
Promise概述
Promise對象是CommonJS工作組提出的一種規(guī)范,目的是為異步操作提供統(tǒng)一接口。
那么,什么是Promises?
首先,它是一個對象,也就是說與其他JavaScript對象的用法,沒有什么兩樣;其次,它起到代理作用(proxy),充當異步操作與回調(diào)函數(shù)之間的中介。它使得異步操作具備同步操作的接口,使得程序具備正常的同步運行的流程,回調(diào)函數(shù)不必再一層層嵌套。
簡單說,它的思想是,每一個異步任務(wù)立刻返回一個Promise對象,由于是立刻返回,所以可以采用同步操作的流程。這個Promises對象有一個then方法,允許指定回調(diào)函數(shù),在異步任務(wù)完成后調(diào)用。
Promise的then方法可以接受前一個函數(shù)的執(zhí)行結(jié)果,還可以保證另一個Promise的順序執(zhí)行,這到底是怎么做到的呢?
原理圖(先上圖)

問題需求
如何保證多個 promise 順序執(zhí)行?
實例:
var f1 = function (){
return new Promise(function (resolve, reject){
setTimeout(function (){
console.log("f1 ok!")
resolve("f1 ok!");
}, 1000)
});
}
var f2 = function (){
return new Promise(function (resolve, reject){
setTimeout(function (){
console.log("f2 ok!")
resolve("f2 ok!");
}, 3000)
});
}
var f3 = function (){
return new Promise(function (resolve, reject){
setTimeout(function (){
console.log("f3 ok!")
resolve("f3 ok!");
}, 2000)
});
}
當然如果要并行的話,我們很容易想到 Promise.all 方法:
Promise.all([f1(), f2(), f3()]).then(function (data){
console.log(data)
})
// f1 ok!
// f3 ok!
// f2 ok!
// ["f1 ok!", "f2 ok!", "f3 ok!"]
如果要順序執(zhí)行:
f1().then(f2).then(f3)
// f1 ok!
// f2 ok!
// f3 ok!
//或者這樣
function f(all) {
var promise = Promise.resolve();
all.forEach((p, index) => {
promise = promise.then(p)
})
}
f([f1, f2, f3])
那么問題來了,then是如何做到順序執(zhí)行的呢,參數(shù)既可以是一個普通函數(shù),也可是是一個返回promise的函數(shù)?
then的奧秘
很多實現(xiàn)promise的庫都比較復(fù)雜,如果自己實現(xiàn)的話,可以借鑒下面簡單的代碼:
Promise.prototype.then = function(onFulfilled, onRejected) {
var promise = this;
return new Promise(function(resolve, reject) {
function handle(value) {
var ret = typeof onFulfilled === 'function' && onFulfilled(value) || value;
if (ret && typeof ret['then'] == 'function') {
ret.then(function(value) {
resolve(value);
}, function(reason) {
reject(reason);
});
} else {
resolve(ret);
}
}
function errback(reason) {
reason = typeof onRejected === 'function' && onRejected(reason) || reason;
reject(reason);
}
if (promise._status === 'PENDING') {
promise._resolves.push(handle);
promise._rejects.push(errback);
} else if (promise._status === FULFILLED) {
callback(promise._value);
} else if (promise._status === REJECTED) {
errback(promise._reason);
}
});
}
重點在then的實現(xiàn),看上述代碼,每個then返回的是什么,是一個新的 Promise,一個新的 Promise,一個新的 Promise
第二個重點是,在內(nèi)部又處理了一個 回調(diào)函數(shù)運行結(jié)果是 一個 promise的 判斷,如果是那么等待這個promise運行結(jié)束才調(diào)用 resolve 更改狀態(tài),關(guān)鍵是resolve的調(diào)用時機,resolve的調(diào)用時機,才能夠往下執(zhí)行,這兩步就是then函數(shù)的關(guān)鍵。
是不是 有點暈,請看最開始的圖。
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。
相關(guān)文章
javascript showModalDialog,open取得父窗口的方法
showModalDialog,open取得父窗口的代碼,需要的朋友可以參考下。2010-03-03
純前端生成PDF(jsPDF)并下載保存或上傳到OSS的代碼示例
這篇文章主要介紹了純前端生成PDF(jsPDF)并下載保存或上傳到OSS的相關(guān)資料,主要步驟包括獲取DOM節(jié)點、生成PDF、保存或上傳PDF,文章還提到了一些注意事項,需要的朋友可以參考下2025-01-01
javascript判斷是手機還是電腦訪問網(wǎng)頁的簡單實例分享
在智能手機越來越普及甚至是泛濫的時候,確實給大家的生活帶來了很大的方便,但是對于web前端設(shè)計師來說,可就麻煩多了,現(xiàn)在很多的網(wǎng)站在制作過程中都要考慮到手機訪問的問題,那么我們?nèi)绾蝸砼袛嗫蛻舳耸遣皇鞘謾C呢,下面分享個例子吧2014-06-06
JavaScript中for?in和for?of的區(qū)別示例詳解
在JavaScript中for...in和for...of是兩種不同的循環(huán)結(jié)構(gòu),它們各自有特定的用途和特點,這篇文章主要介紹了JavaScript中for?in和for?of區(qū)別的相關(guān)資料,需要的朋友可以參考下2025-06-06
javascript命名約定(變量?函數(shù)?類?組件)
這篇小文章主要是通過一些例子來介紹一些Javascript中一些關(guān)于命名變量,函數(shù),類或者是組件的通用約定,雖然這些規(guī)則并不是強制性的,但是呢,他們卻被一些JS社區(qū)所廣泛采用,所以,了解他們還是很有必要的2023-03-03
JavaScript實現(xiàn)帶箭頭標識的多級下拉菜單效果
這篇文章主要介紹了JavaScript實現(xiàn)帶箭頭標識的多級下拉菜單效果,可實現(xiàn)橫向與縱向箭頭的形式標識選中菜單項位置的功能,涉及javascript針對頁面元素位置的判定與樣式動態(tài)操作技巧,需要的朋友可以參考下2015-08-08
JS和Canvas實現(xiàn)圖片的預(yù)覽壓縮和上傳功能
這篇文章主要介紹了JS和Canvas實現(xiàn)圖片的預(yù)覽壓縮和上傳功能,實現(xiàn)此功能大概有兩步,第一步用戶選擇需要上傳的圖片,第二步獲取圖片資源壓縮預(yù)覽上傳,具體實現(xiàn)代碼大家參考下本文2018-03-03

