JavaScript 筆記五:同步、異步、Promise

都是本人理解,筆記大致概念,不詳細(xì)也并非完全正確,所以僅供參考。


同步、異步

JS 代碼的執(zhí)行,可以理解為任務(wù)的執(zhí)行,則其中有同步任務(wù)和異步任務(wù)。

同步任務(wù)是指在主線程上的任務(wù),只有前面一個(gè)執(zhí)行完畢,才會(huì)再執(zhí)行下一個(gè)。
同步任務(wù)好理解,異步任務(wù)的執(zhí)行主要是以下步驟:

  1. 主線程任務(wù)進(jìn)行,若發(fā)現(xiàn)異步任務(wù),將其移入任務(wù)隊(duì)列
  2. 主線程任務(wù)結(jié)束,開始執(zhí)行任務(wù)隊(duì)列的異步任務(wù)
  3. 任務(wù)隊(duì)列任務(wù)進(jìn)行,若發(fā)現(xiàn)異步任務(wù),將其移入任務(wù)隊(duì)列后
  4. 重復(fù)步驟3直至沒有任務(wù)隊(duì)列沒有任務(wù),結(jié)束。

Promise

都知道異步任務(wù)的 callback 的循環(huán)嵌套會(huì)讓人抓狂,所以就有了 Promise,Promise主要解決了JS異步任務(wù)代碼的可讀性問(wèn)題。

Promise 的三種狀態(tài)

  • pending:初始狀態(tài),非成功或失敗
  • fulfilled:操作成功完成
  • rejected:操作失敗

Promise 的狀態(tài)的改變是不可逆的,所以它只會(huì)有:

  • pending -> fulfilled
  • pending -> rejected

同步、異步、Promise 的執(zhí)行順序

有個(gè)問(wèn)題,Promise 是不是異步操作?先看代碼:

setTimeout(() => {
  console.log(1);
}, 0);
new Promise(resolve => {
  console.log(2);
  resolve();
  console.log(3);
}).then(res => {
  console.log(4);
});
console.log(5);

正確結(jié)果是:2、3、5、4、1 ,來(lái)一一解析。

先忽略1和5,如果說(shuō) Promise 是同步的,那么應(yīng)該是 2、4、3,但結(jié)果為什么是2、3、4?
猜想是 Promise 將 resolve(); 的方法加了某種延遲,這種延遲不加入任務(wù)隊(duì)列,而僅僅是等待 Promise 初始化函數(shù)結(jié)束而開始執(zhí)行,所以結(jié)果是 2、3、4。

實(shí)際上,這種操作是存在的,稱之為微任務(wù),微任務(wù)的執(zhí)行順序介于主線程和任務(wù)隊(duì)列之間。
PS:任務(wù)隊(duì)列的任務(wù)也稱之為宏任務(wù)

所以,在上述代碼中,1被插入任務(wù)隊(duì)列等待,而 Promise 初始函數(shù)先輸出 2,再因?yàn)?resolve(); 為微任務(wù)而先輸出3,然后因?yàn)槲⑷蝿?wù)的執(zhí)行順序低于主線程,所以輸出 5,最后微任務(wù)執(zhí)行完畢,執(zhí)行 then 輸出 4,最后才執(zhí)行到任務(wù)隊(duì)列,輸出 1,所以最后的結(jié)果是:2、3、5、4、1。

如果宏任務(wù)包含微任務(wù),那么先后順序是?
答案:執(zhí)行宏任務(wù) > 執(zhí)行包含的微任務(wù) > 執(zhí)行下一個(gè)宏任務(wù)。

new Promise(resolve1 => {
  console.log(1);
  setTimeout(() => {
    resolve1();
  }, 0);
  setTimeout(() => {
    console.log(2);
  }, 0);
})
  .then(() => {
    return new Promise(resolve2 => {
      resolve2();
      console.log(3);
    });
  })
  .then(() => {
    console.log(4);
  });
console.log(5);

答案?1、5、3、4、2

解析一下:主線程進(jìn)行,Promise 初始化函數(shù)里輸出 1,將宏任務(wù) setTimeout - resolve1(); 和setTimeout - 2 放入隊(duì)列,輸出 5,主線程結(jié)束,執(zhí)行宏任務(wù)setTimeout - resolve1(); ,執(zhí)行宏任務(wù)下的微任務(wù) resolve1() > then,新的 Promise 的執(zhí)行函數(shù)中,輸出 3,發(fā)現(xiàn)微任務(wù) resolve2(),執(zhí)行 then 輸出4,此宏任務(wù)結(jié)束,下一個(gè)宏任務(wù) setTimeout - 2 ,輸出 2,結(jié)束。

總結(jié)

Promise并非異步的,僅僅因?yàn)閞esolve和reject方法為微操作,所以會(huì)先執(zhí)行初始函數(shù)體,進(jìn)而再執(zhí)行then,所以會(huì)讓人誤以為是異步的。


ES5 寫 Promise

貼代碼總覺得不夠深層,寫一下自己的理解,參照 Promise 的三種狀態(tài),可以知道有這些屬性。

  • 狀態(tài):記錄 Promise 的狀態(tài)
  • 成功值:成功后的返回值
  • 失敗值:失敗后的返回值
  • 成功回調(diào)方法:成功后的執(zhí)行方法,即 then
  • 失敗回調(diào)方法:失敗后的執(zhí)行方法,即 catch
  • resolve方法:切換狀態(tài)至成功,并執(zhí)行成功回調(diào)方法
  • reject方法:切換狀態(tài)至失敗,并執(zhí)行失敗回調(diào)方法
  • then方法:傳入成功回調(diào)方法和失敗函數(shù)方法,將此存儲(chǔ)Promise中,切換狀態(tài)時(shí)進(jìn)行對(duì)應(yīng)調(diào)用。

過(guò)程

  • 當(dāng) new 一個(gè) Promise 時(shí),將初始函數(shù)執(zhí)行,然后將 then 或 catch 的回調(diào)函數(shù)存儲(chǔ),當(dāng)切換狀態(tài)成功或切換狀態(tài)失敗函數(shù)時(shí),取出存儲(chǔ)的成功回調(diào)或失敗回調(diào)進(jìn)行執(zhí)行。
  • 像 then 的鏈?zhǔn)秸{(diào)用,實(shí)質(zhì)是返回一個(gè)新的 Promise 即可。
  • then 的支持傳入成功和失敗回調(diào),而 catch 實(shí)際上是執(zhí)行 then 且僅傳入失敗回調(diào)。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 弄懂js異步 講異步之前,我們必須掌握一個(gè)基礎(chǔ)知識(shí)-event-loop。 我們知道JavaScript的一大特點(diǎn)...
    DCbryant閱讀 2,891評(píng)論 0 5
  • 官方中文版原文鏈接 感謝社區(qū)中各位的大力支持,譯者再次奉上一點(diǎn)點(diǎn)福利:阿里云產(chǎn)品券,享受所有官網(wǎng)優(yōu)惠,并抽取幸運(yùn)大...
    HetfieldJoe閱讀 11,152評(píng)論 26 95
  • 你不知道JS:異步 第三章:Promises 在第二章,我們指出了采用回調(diào)來(lái)表達(dá)異步和管理并發(fā)時(shí)的兩種主要不足:缺...
    purple_force閱讀 2,261評(píng)論 0 4
  • 本文作者就是我,簡(jiǎn)書的microkof。如果您覺得本文對(duì)您的工作有意義,產(chǎn)生了不可估量的價(jià)值,那么請(qǐng)您不吝打賞我,...
    microkof閱讀 16,071評(píng)論 9 40
  • 列表LIST 認(rèn)識(shí)list 列表是有序、可變的容器類型(元素?cái)?shù)量、值可變),內(nèi)部的元素可以任何類型. 列表是一種序...
    rzlong閱讀 236評(píng)論 0 1

友情鏈接更多精彩內(nèi)容