您好,登錄后才能下訂單哦!
這篇文章主要介紹了Promise指的是什么,具有一定借鑒價值,需要的朋友可以參考下。希望大家閱讀完這篇文章后大有收獲。下面讓小編帶著大家一起了解一下。
Promise 關(guān)于 API 這塊大家應該都能熟練使用,但是和微任務相關(guān)的你可能還存在知識盲區(qū)。
在開始正文前,我們先把本文涉及到的一些內(nèi)容提前定個基調(diào)。
Promise 中只有涉及到狀態(tài)變更后才需要被執(zhí)行的回調(diào)才算是微任務,比如說 then
、 catch
、finally
,其他所有的代碼執(zhí)行都是宏任務(同步執(zhí)行)。
上圖中藍色為同步執(zhí)行,黃色為異步執(zhí)行(丟到微任務隊列中)。
這個問題我們根據(jù) ecma 規(guī)范來看:
如果此時 Promise 狀態(tài)為 pending,那么成功或失敗的回調(diào)會分別被加入至 [[PromiseFulfillReactions]]
和 [[PromiseRejectReactions]]
中。如果你看過手寫 Promise 的代碼的話,應該能發(fā)現(xiàn)有兩個數(shù)組存儲這些回調(diào)函數(shù)。
如果此時 Promise 狀態(tài)為非 pending 時,回調(diào)會成為 Promise Jobs,也就是微任務。
了解完以上知識后,正片開始。
Promise.resolve() .then(() => { console.log("then1"); Promise.resolve().then(() => { console.log("then1-1"); }); }) .then(() => { console.log("then2"); });復制代碼
以上代碼大家應該都能得出正確的答案:then1 → then1-1 → then2
。
雖然 then
是同步執(zhí)行,并且狀態(tài)也已經(jīng)變更。但這并不代表每次遇到 then
時我們都需要把它的回調(diào)丟入微任務隊列中,而是等待 then
的回調(diào)執(zhí)行完畢后再根據(jù)情況執(zhí)行對應操作。
基于此,我們可以得出第一個結(jié)論:鏈式調(diào)用中,只有前一個 then
的回調(diào)執(zhí)行完畢后,跟著的 then
中的回調(diào)才會被加入至微任務隊列。
大家都知道了 Promise resolve
后,跟著的 then
中的回調(diào)會馬上進入微任務隊列。
那么以下代碼你認為的輸出會是什么?
let p = Promise.resolve(); p.then(() => { console.log("then1"); Promise.resolve().then(() => { console.log("then1-1"); }); }).then(() => { console.log("then1-2"); }); p.then(() => { console.log("then2"); }); 復制代碼
按照一開始的認知我們不難得出 then2
會在 then1-1
后輸出,但是實際情況卻是相反的。
基于此我們得出第二個結(jié)論:每個鏈式調(diào)用的開端會首先依次進入微任務隊列。
接下來我們換個寫法:
let p = Promise.resolve().then(() => { console.log("then1"); Promise.resolve().then(() => { console.log("then1-1"); }); }).then(() => { console.log("then2"); }); p.then(() => { console.log("then3"); });復制代碼
上述代碼其實有個陷阱,then
每次都會返回一個新的 Promise,此時的 p
已經(jīng)不是 Promise.resolve()
生成的,而是最后一個 then
生成的,因此 then3
應該是在 then2
后打印出來的。
順便我們也可以把之前得出的結(jié)論優(yōu)化為:同一個 Promise 的每個鏈式調(diào)用的開端會首先依次進入微任務隊列。
以下大家可以猜猜 then1-2
會在何時打印出來?
Promise.resolve() .then(() => { console.log("then1"); Promise.resolve() .then(() => { console.log("then1-1"); return 1; }) .then(() => { console.log("then1-2"); }); }) .then(() => { console.log("then2"); }) .then(() => { console.log("then3"); }) .then(() => { console.log("then4"); });復制代碼
這題肯定是簡單的,記住第一個結(jié)論就能得出答案,以下是解析:
第一次 resolve
后第一個 then
的回調(diào)進入微任務隊列并執(zhí)行,打印 then1
第二次 resolve
后內(nèi)部第一個 then
的回調(diào)進入微任務隊列,此時外部第一個 then
的回調(diào)全部執(zhí)行完畢,需要將外部的第二個 then
回調(diào)也插入微任務隊列。
執(zhí)行微任務,打印 then1-1
和 then2
,然后分別再將之后 then
中的回調(diào)插入微任務隊列
執(zhí)行微任務,打印 then1-2
和 then3
,之后的內(nèi)容就不一一說明了
接下來我們把 return 1
修改一下,結(jié)果可就大不相同啦:
Promise.resolve() .then(() => { console.log("then1"); Promise.resolve() .then(() => { console.log("then1-1"); return Promise.resolve(); }) .then(() => { console.log("then1-2"); }); }) .then(() => { console.log("then2"); }) .then(() => { console.log("then3"); }) .then(() => { console.log("then4"); });復制代碼
當我們 return Promise.resolve()
時,你猜猜 then1-2
會何時打印了?
答案是最后一個才被打印出來。
為什么在 then
中分別 return
不同的東西,微任務的執(zhí)行順序竟有如此大的變化?以下是筆者的解析。
PS:then
返回一個新的 Promise,并且會用這個 Promise 去 resolve
返回值,這個概念需要大家先了解一下。
根據(jù)規(guī)范 2.3.2,如果 resolve
了一個 Promise,需要為其加上一個 then
并 resolve
。
if (x instanceof MyPromise) { if (x.currentState === PENDING) { } else { x.then(resolve, reject); } return; }復制代碼
上述代碼節(jié)選自手寫 Promise 實現(xiàn)。
那么根據(jù) A+ 規(guī)范來說,如果我們在 then
中返回了 Promise.resolve
的話會多入隊一次微任務,但是這個結(jié)論還是與實際不符的,因此我們還需要尋找其他權(quán)威的文檔。
根據(jù)規(guī)范 25.6.1.3.2,當 Promise resolve
了一個 Promise 時,會產(chǎn)生一個NewPromiseResolveThenableJob,這是屬于 Promise Jobs 中的一種,也就是微任務。
This Job uses the supplied thenable and its then method to resolve the given promise. This process must take place as a Job to ensure that the evaluation of the then method occurs after evaluation of any surrounding code has completed.
并且該 Jobs 還會調(diào)用一次 then
函數(shù)來 resolve Promise
,這也就又生成了一次微任務。
這就是為什么會觸發(fā)兩次微任務的來源。
感謝你能夠認真閱讀完這篇文章,希望小編分享Promise指的是什么內(nèi)容對大家有幫助,同時也希望大家多多支持億速云,關(guān)注億速云行業(yè)資訊頻道,遇到問題就找億速云,詳細的解決方法等著你來學習!
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。