<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          關(guān)于 Promise 的執(zhí)行順序

          共 2729字,需瀏覽 6分鐘

           ·

          2022-01-22 02:31

          最近看到一個(gè) Promise 相關(guān)的很有意思的代碼:
          new?Promise((resolve)?=>?{
          ??console.log(1)
          ??resolve()
          }).then(()?=>?{
          ??new?Promise((resolve)?=>?{
          ????console.log(2)
          ????resolve()
          ??}).then(()?=>?{
          ????console.log(4)
          ??})
          }).then(()?=>?{
          ??console.log(3)
          })

          第一次看到這個(gè)代碼的時(shí)候,以為的輸出結(jié)果會(huì)是:1,2,3,4,但是被實(shí)際的輸出結(jié)果打臉 。

          如圖所示,實(shí)際的輸出結(jié)果為:1,2,4,3

          代碼分析

          為了搞清楚實(shí)際的輸出結(jié)果為什么是:1,2,4,3,我們來(lái)一步步分析代碼的執(zhí)行。

          我們知道,Promise 實(shí)例化時(shí),傳入的回調(diào)會(huì)立即執(zhí)行,而Promise 的 then 回調(diào)會(huì)被放到微任務(wù)隊(duì)列中,等待執(zhí)行。隊(duì)列就是一個(gè)先進(jìn)先出的列表,先被放到隊(duì)列的回調(diào),會(huì)被優(yōu)先執(zhí)行。前面的代碼中,一共有 5 個(gè)回調(diào)函數(shù)。

          回調(diào)1 是 Promise 實(shí)例化時(shí)的回調(diào),所以會(huì)立即執(zhí)行,此時(shí)控制臺(tái)打印出數(shù)字 1,然后 resolve() 方法被調(diào)用,此時(shí)的 Promise 狀態(tài)被修改成了 fulfilled(如果沒(méi)有調(diào)用 resolve() 方法,Promise 的狀態(tài)為 pending)。

          Promise 實(shí)例化完成后,第一個(gè) then() 方法被調(diào)用, 回調(diào)2 會(huì)被放入了微任務(wù)隊(duì)列中,等待執(zhí)行。

          then 方法何時(shí)調(diào)用?

          這個(gè)時(shí)候疑問(wèn)點(diǎn)來(lái)了,第一個(gè) then() 方法被調(diào)用后,第二個(gè) then 方法會(huì)不會(huì)馬上被調(diào)用,如果會(huì),那輸出的結(jié)果就應(yīng)該是 :1,2,3,4。顯然,此時(shí)不會(huì)馬上調(diào)用第二個(gè) then() 方法,也就是不會(huì)馬上將 回調(diào)5 放入微任務(wù)隊(duì)列。那如果不會(huì),那何時(shí)才會(huì)被調(diào)用?

          這個(gè)時(shí)候,需要看一下 Promise/A+ 規(guī)范。重點(diǎn)是下面幾條:

          2.2 then 方法promise 的 then 方法接受兩個(gè)參數(shù):

          promise.then(onFulfilled,?onRejected)

          2.2.2 如果 onFulfilled 是函數(shù):

          • 2.2.2.1 當(dāng) promise 處于已處理狀態(tài)時(shí),該函數(shù)必須被調(diào)用并將 promise 的值作為第一個(gè)參數(shù)。
          • 2.2.2.2 該函數(shù)一定不能在 promise 處于已處理狀態(tài)之前調(diào)用。
          • 2.2.2.3 該函數(shù)被調(diào)用次數(shù)不超過(guò)一次。

          2.2.6 then 可以在同一個(gè) promise 上多次調(diào)用。

          • 2.2.6.1 如果 promise 處于已處理狀態(tài)時(shí),所有相應(yīng)的 onFulfilled 回調(diào)必須按照它們對(duì) then 的組織順序依次調(diào)用。
          • 2.2.6.2 如果 promise 處于已拒絕狀態(tài)時(shí),所有相應(yīng)的 onRejected 回調(diào)必須按照它們對(duì) then 的組織順序依次調(diào)用。

          2.2.7 then 必須返回一個(gè) promise。

          promise1?=?new?Promise(resolve?=>?resolve())

          //?promise1?可以多次調(diào)用?then
          //?且 onFulfilled 回調(diào)的執(zhí)行順序,按照 .then 的調(diào)用順序執(zhí)行
          promise1.then(onFulfilled1)?//?1
          promise1.then(onFulfilled2)?//?2
          promise1.then(onFulfilled3)?//?3
          //?上面?3?個(gè)?onFulfilled,按照?1、2、3?的順序執(zhí)行
          //?調(diào)用?.then?方法后,返回一個(gè)新的?promise
          promise2?=?promise1.then(onFulfilled,?onRejected);

          綜上,第一個(gè) then() 方法調(diào)用后,會(huì)返回一個(gè)新的 Promise。這樣做的目的就是為了保持鏈?zhǔn)秸{(diào)用,而且 then() 方法內(nèi)的 onFulfilled 回調(diào)會(huì)等待 Promise 狀態(tài)修改之后才會(huì)調(diào)用。

          我們稍微修改一下前面代碼的調(diào)用形式,如下:

          const?p1?=?new?Promise((resolve)?=>?{
          ??console.log(1)
          ??resolve()
          })

          const?p2?=?p1.then(()?=>?{
          ??new?Promise((resolve)?=>?{
          ????console.log(2)
          ????resolve()
          ??}).then(()?=>?{
          ????console.log(4)
          ??})
          })

          const?p3?=?p2.then(()?=>?{
          ??console.log(3)
          })

          p1.then() 會(huì)返回一個(gè)新的 Promise 命名為 p2,后面的 p2.then() 的回調(diào)會(huì)在 p1.then() 內(nèi)的回調(diào)函數(shù)執(zhí)行完之后,才會(huì)調(diào)用,也就是 p2 這個(gè) Promise 狀態(tài)發(fā)生改變之后。

          所以,只有 回調(diào)2 執(zhí)行完成后,才會(huì)執(zhí)行 p2.then()。我們?cè)倏?回調(diào)2 的內(nèi)容。

          回調(diào)2 先是對(duì)一個(gè) Promise 進(jìn)行了實(shí)例化操作,實(shí)例化的回調(diào)為 回調(diào)3 ,該回調(diào)會(huì)立即執(zhí)行,此時(shí)控制臺(tái)打印出數(shù)字 2,然后 resolve() 方法被調(diào)用,此時(shí)的 Promise 狀態(tài)被修改成了 fulfilled,后面的 回調(diào)4 會(huì)放入微任務(wù)隊(duì)列。回調(diào)2 執(zhí)行完畢后,執(zhí)行 p2.then()回調(diào)5 被放入微任務(wù)隊(duì)列。

          按照隊(duì)列先進(jìn)先出的執(zhí)行順序,先執(zhí)行 回調(diào)4,然后執(zhí)行 回調(diào)5。所以,在控制臺(tái)會(huì)先輸出數(shù)字 4,然后輸出數(shù)字 3

          如果想要輸出的結(jié)果為:1,2,3,4,可以將代碼改成如下形式:

          const?p1?=?new?Promise((resolve)?=>?{
          ??console.log(1)
          ??resolve()
          })

          p1.then(()?=>?{
          ??new?Promise((resolve)?=>?{
          ????console.log(2)
          ????resolve()
          ??}).then(()?=>?{
          ????console.log(4)
          ??})
          })

          p1.then(()?=>?{
          ??console.log(3)
          })

          根據(jù)前面的 2.2.6 規(guī)則,then 可以在同一個(gè) promise 上多次調(diào)用,且 p1 后面的 then 會(huì)按照他們的調(diào)用順序直接放入微任務(wù)隊(duì)列中。

          - END -


          瀏覽 56
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  日韩人妻无码中文字幕 | 国产变态视频a片一二三 | 国产免费黄色电影 | 亚洲一级a免费在线观看 | AA片视频 |