這篇文章動機(jī)是為了解釋這個問題
往下閱讀之前你需要知道,promise的resolve回調(diào)函數(shù)會被放在job queue中等待主任務(wù)執(zhí)行完畢后等待執(zhí)行(這也是文章提到的問題的解答)。可以參考這篇文章
代碼一new Promise((resolve, reject) => { resolve(); //將resolved回調(diào)函數(shù)(then的第一個參數(shù))添加到queue隊(duì)列 }).then(() => { console.log("promise1 resolved"); }); new Promise((resolve, reject) => { resolve(); //將resolved回調(diào)函數(shù)(then的第一個參數(shù))添加到queue隊(duì)列 }).then(() => { console.log("promise3 resoved"); }); console.log("main"); //result: //main //promise1 resolved //promise3 resoved
這個結(jié)果很好理解,兩個resolve()函數(shù)將兩個回調(diào)函數(shù)依次添加到j(luò)ob queue隊(duì)列,主任務(wù)隊(duì)列執(zhí)行完后,依次執(zhí)行job queue中的任務(wù)。
代碼二在看代碼前首先要理解promise then函數(shù)的返回值也是一個promise,而返回的promise的狀態(tài)(pending,resolved,reject)在不同情況下會是不同的值,具體請參考MDN上的解釋。為方便理解,請大家記住下面這段代碼中的then函數(shù)的返回值均是處于resolved狀態(tài)的promise。并請牢記一個promise如果是resolved狀態(tài)則它會將其then回調(diào)函數(shù)作為一個任務(wù)添加到j(luò)ob queue。為方便解釋,我會在代碼中將每個then函數(shù)標(biāo)記為一個任務(wù),希望大家能對照著看。OK,讓我們來看代碼
new Promise((resolve, reject) => { resolve(); //resolve_1 }).then(() => { // then_task_1 console.log("promise1 resolved"); }).then(() => { // then_task_2 console.log("promise2 resolved"); }).then(() => { // then_task_3 console.log("promise3 resolved"); }); new Promise((resolve, reject) => { resolve(); //resolve_2 }).then(() => { // then_task_x console.log("promisex resolved"); }).then(() => { // then_task_y console.log("promisey resolved"); }).then(() => { // then_task_z console.log("promisez resolved"); }); console.log("main"); //result: //main //promise1 resolved //promisex resolved //promise2 resolved //promisey resolved //promise3 resolved //promisez resolved
1,首先resolve_1將then_task_1添加到j(luò)ob queue,然后resolve2將then_task_x添加到j(luò)ob queue。然后執(zhí)行到console.log("main")。
主任務(wù)隊(duì)列中的任務(wù)執(zhí)行完成,主任務(wù)隊(duì)列空(是的,這時job queue中只有then_task_1和then_task_x)。
2,開始執(zhí)行job queue中的任務(wù):執(zhí)行then_task_1,打印promise1,這時返一個resolved promise,這個promise的then是then_task_2,js將then_task_2添加到then_task_x后;執(zhí)行then_task_x,打印promisx,同理將then_task_y添加到then_task_2后。依次類推,我們就看到了代碼結(jié)果這樣的打印順序。
new Promise((resolve, reject) => { resolve(Promise.resolve().then(() => { //then_task_innner console.log("inner promise resolved") })); //外層resolve對應(yīng)then_task1,內(nèi)層resolve對應(yīng)then_task_inner }).then(() => { //then_task_1 console.log("promise1 resolved"); }); new Promise((resolve, reject) => { resolve(); //resolve2 }).then(() => { //then_task_2 console.log("promise2 resolved"); }); console.log("main"); //result: //main //inner promise resolved //promise2 resolved //promise1 resolved
這段代碼執(zhí)行到第一個resolve時發(fā)現(xiàn)其參數(shù)是一個resolved promise的then回調(diào)函數(shù),這個參數(shù)是無法立即計算出值來的(因?yàn)檫@個then_task_innner被添加到j(luò)ob queue不會被立即執(zhí)行)。所以這個resolve函數(shù)不會被立即執(zhí)行。所以到這里then_task_innner被添加到j(luò)ob queue了,但是then_task_1并沒有,因?yàn)槠鋵?yīng)的promise還處于pending狀態(tài),沒有被resolve。然后執(zhí)行到resolve2,將then_task_2添加到j(luò)ob queue。然后執(zhí)行console.log("main"),主任務(wù)隊(duì)列完成。這時job queue中有then_task_inner和then_task_2。當(dāng)執(zhí)行完then_task_inner后,第一個resolve()會被添加到j(luò)ob queue,這時job queue中只有resolve()這個任務(wù),這個resolve被執(zhí)行。其對應(yīng)的promise變?yōu)閞esolved狀態(tài),對應(yīng)的then_task_1被添加到j(luò)ob queue中,然后被執(zhí)行。因此我們看到屏幕上的打印結(jié)果是這樣的。
代碼四有了代碼三的鋪墊,我們現(xiàn)在來看看下面這段代碼。
new Promise((resolve, reject) => { resolve(Promise.resolve()); //為方便解釋,我們將外層的resolve叫做 outer_resolve;內(nèi)層的resolve叫做inner_resolve }).then(() => { //promise1_task console.log("promise1 resolved"); }); new Promise((resolve, reject) => { resolve(); //resolve2 對應(yīng) promise2_task }).then(() => { //promise2_task console.log("promise2 resolved"); }).then(() => { //promise3_task console.log("promise3 resolved"); }); console.log("main"); //result: //main //promise2 resolved //promise3 resolved //promise1 resolved
放這段代碼是為了過渡,方便解釋下面的問題。
這段代碼對比代碼三inner_resolve沒有了.then();不過并不是沒有了,我們可以理解為inner_resolve對應(yīng)的promise的then函數(shù)是null。
程序首先運(yùn)行到第一個resolve,發(fā)現(xiàn)無法立即獲得參數(shù)值,對應(yīng)的promise無法改變狀態(tài),任然是pendding,所以對應(yīng)的promise1_task不會被添加到j(luò)ob queue。然而inner_resolve被執(zhí)行了,其對應(yīng)的then函數(shù)(null)被添加到j(luò)ob queue。接下來第二個resolve被執(zhí)行,對應(yīng)的promise2_task被添加到j(luò)ob queue。之后主任務(wù)執(zhí)行完成,開始執(zhí)行job queue中的任務(wù)。對一個任務(wù)是null,執(zhí)行完后因?yàn)榈谝粋€resolve的參數(shù)有了,所以這個resolve函數(shù)被添加到j(luò)ob queue中;接下來是執(zhí)行promise2_task,打印promise2 并將promise3_task添加到j(luò)ob queue。然后執(zhí)行第一個resolve函數(shù),其對應(yīng)的promise1_task被添加到j(luò)ob queue。接下來是執(zhí)行promise3_task,然后promise1_task。
如果我們將resolve(Promise.resolve())換成resolve()。就會看到打印結(jié)果順序是promise1,promise2,promise3。
new Promise((resolve, reject) => { console.log("async1 start"); console.log("async2"); resolve(Promise.resolve()); //這里的Promise.resolve會添加一個null任務(wù)到j(luò)ob queue,外層resolve對應(yīng)async1_end_task }).then(() => { //async1_end_task console.log("async1 end"); }); new Promise(function(resolve) { console.log("promise1"); resolve(); //對應(yīng)promise2_task }).then(function() { //promise2_task console.log("promise2"); }).then(function() { //promise3_task console.log("promise3"); }).then(function() { //promise4_task console.log("promise4"); }); //result: //async1 start //async2 //promise1 //promise2 //promise3 //async1 end //promise4
這里我們對async1 start,async2,promise1的打印順序不解釋,這時在主任務(wù)中執(zhí)行的,按主任務(wù)執(zhí)行順序打印。
romise2,promise3,async1 end,promise4的打印順序解釋同代碼四
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/99058.html
摘要:如果你要問他和誰當(dāng)進(jìn)去的快,要從下面兩個方面考慮結(jié)束時。至于什么,查了很多的資料,了解到一個瀏覽器環(huán)境只能有一個事件循環(huán),而一個事件循環(huán)可以有多個任務(wù)隊(duì)列。 ====據(jù)說這是今日頭條去年的一道筆試題,主要考察的是setTimeout async promise執(zhí)行順序 ~先雙手奉上這道題目~ async function async1() { consol...
摘要:想必面試題刷的多的同學(xué)對下面這道題目不陌生,能夠立即回答出輸出個,可是你真的懂為什么嗎為什么是輸出為什么是輸出個這兩個問題在我腦邊縈繞。同步任務(wù)都好理解,一個執(zhí)行完執(zhí)行下一個。本文只是我對這道面試題的一點(diǎn)思考,有誤的地方望批評指正。 想必面試題刷的多的同學(xué)對下面這道題目不陌生,能夠立即回答出輸出10個10,可是你真的懂為什么嗎?為什么是輸出10?為什么是輸出10個10?這兩個問題在我腦...
摘要:問題是處理完了,卻也引發(fā)了自己的一些思考處理的異步操作,都有一些什么方法呢一回調(diào)函數(shù)傳說中的就是來自回調(diào)函數(shù)。而回調(diào)函數(shù)也是最基礎(chǔ)最常用的處理異步操作的辦法。 引言 js的異步操作,已經(jīng)是一個老生常談的話題,關(guān)于這個話題的文章隨便google一下都可以看到一大堆。那么為什么我還要寫這篇東西呢?在最近的工作中,為了編寫一套相對比較復(fù)雜的插件,需要處理各種各樣的異步操作。但是為了體積和兼容...
摘要:進(jìn)一步最終定位發(fā)現(xiàn)如果為的時候,效率驟降,如果為合法的字符串的時候,效率是正常值。每次執(zhí)行該子句都會發(fā)生這種情況,將捕獲的異常對象分配給一個變量。盡可能將它們與其他代碼隔離,以免影響其性能。關(guān)鍵代碼拆解成如下圖所示(無關(guān)部分已省略):起初我認(rèn)為可能是這個 getRowDataItemNumberFormat 函數(shù)里面某些方法執(zhí)行太慢,從 formatData.replace 到 unesca...
摘要:好吧,本文的主題可能還深入剖析的深復(fù)制前端掘金一年前我曾寫過一篇中的一種深復(fù)制實(shí)現(xiàn),當(dāng)時寫這篇文章的時候還比較稚嫩,有很多地方?jīng)]有考慮仔細(xì)。 翻譯 | 深入理解 CSS 時序函數(shù) - 前端 - 掘金作者:Nicolas(滬江前端開發(fā)工程師) 本文原創(chuàng),轉(zhuǎn)載請注明作者及出處。 各位,趕緊綁住自己并緊緊抓牢了,因?yàn)楫?dāng)你掌握了特別有趣但又復(fù)雜的CSS時序函數(shù)之后,你將會真正體驗(yàn)到豎起頭發(fā)般的...
閱讀 3616·2021-11-24 09:39
閱讀 2546·2021-11-15 11:37
閱讀 2211·2021-11-11 16:55
閱讀 5155·2021-10-14 09:43
閱讀 3703·2021-10-08 10:05
閱讀 3006·2021-09-13 10:26
閱讀 2327·2021-09-08 09:35
閱讀 3535·2019-08-30 15:55