promise、async、await、settimeout異步原理與執行順序


一道經典的前端筆試題,你能一眼寫出他們的執行結果嗎?

       async function async1() {
            console.log("async1 start");
            await  async2();
            console.log("async1 end");

          }
          async  function async2() {
            console.log( 'async2');
          }
          console.log("script start");
          setTimeout(function () {
            console.log("settimeout");
          },0);
          async1();
          new Promise(function (resolve) {
            console.log("promise1");
            resolve();
          }).then(function () {
            console.log("promise2");
          });
          console.log('script end');

 

首先第一個問題: JavaScript運行機制是什么?

詳細可參考:https://baijiahao.baidu.com/s?id=1615713540466951098&wfr=spider&for=pc

總結幾點就是:

  1. JavaScript語言是單線程的,同一個時間只能做一件事;
  2. 遵循事件循環機制,當JS解析執行時,會被引擎分為兩類任務,同步任務(synchronous) 和 異步任務(asynchronous)。對於同步任務來說,會被推到執行棧按順序去執行這些任務。對於異步任務來說,當其可以被執行時,會被放到一個 任務隊列(task queue) 里等待JS引擎去執行。當執行棧中的所有同步任務完成后,JS引擎才會去任務隊列里查看是否有任務存在,並將任務放到執行棧中去執行,執行完了又會去任務隊列里查看是否有已經可以執行的任務。這種循環檢查的機制,就叫做事件循環(Event Loop)。對於任務隊列,其實是有更細的分類。其被分為 微任務(microtask)隊列 & 宏任務(macrotask)隊列。

 

第二個問題:Promise的原理和運行機制是什么?

古人雲:“君子一諾千金”,這種“承諾將來會執行”的對象在JavaScript中稱為Promise對象。

Promise 是異步編程的一種解決方案,其實是一個構造函數,自己身上有all、reject、resolve這幾個方法,原型上有then、catch等方法。

參考:https://blog.csdn.net/qq_37860963/article/details/81539118

這里擴展一個問題:什么是異步呢?

同步就是一件事一件事的執行。只有前一個任務執行完畢,才能執行后一個任務。

js代碼只能一行一行的執行,不能在同一時間執行多個js代碼任務,這就導致如果有一段耗時較長的計算,或者是一個ajax請求等IO操作,如果沒有異步的存在,就會出現用戶長時間等待,並且由於當前任務還未完成,所以這時候所有的其他操作都會無響應,這時候就需要異步任務。

參考:https://blog.csdn.net/li123128/article/details/80650256

Promise運行順序總結:

  • promise的構造函數是同步執行,promise.then中的函數是異步執行。
  • 構造函數中的 resolve 或 reject 只有第一次執行有效,多次調用沒有任何作用。promise狀態一旦改變則不能再變。
  • promise 的 .then 或者 .catch 可以被調用多次,但這里 Promise 構造函數只執行一次。或者說 promise 內部狀態一經改變,並且有了一個值,那么后續每次調用 .then 或者 .catch 都會直接拿到該值。
  • 如果在一個then()中沒有返回一個新的promise,則 return 什么下一個then就接受什么,如果then中沒有return,則默認return的是 undefined.
  • then()的嵌套會先將內部的then()執行完畢再繼續執行外部的then();
  • catch和then的連用,如果每一步都有可能出現錯誤,那么就可能出現catch后面接上then的情況。如果在catch中也拋出了錯誤,則后面的then的第一個函數不會執行,因為返回的 promise狀態已經為rejected了

 

第三個問題:async、await執行順序?

什么是Async/Await?

  • async/await是寫異步代碼的新方式,以前的方法有回調函數Promise
  • async/await是基於Promise實現的,它不能用於普通的回調函數。
  • async/await與Promise一樣,是非阻塞的。
  • async/await使得異步代碼看起來像同步代碼,這正是它的魔力所在。
  • await關鍵字只能用在aync定義的函數內。async函數會隱式地返回一個promise,該promise的reosolve值就是函數return的值。

執行順序:

使用 async 定義的函數,當它被調用時,它返回的其實是一個 Promise 對象。(當這個 async 函數返回一個值時,Promise 的 resolve 方法會負責傳遞這個值;當 async 函數拋出異常時,Promise 的 reject 方法也會傳遞這個異常值。)

await是一個讓出線程的標志。await后面的函數會先執行一遍,然后就會跳出整個async函數來執行后面js棧的代碼,等本輪事件循環執行完了之后又會跳回到async函數中等待await后面表達式的返回值,如果返回值為非promise則繼續執行async函數后面的代碼,否則將返回的promise放入promise隊列。

參考:https://segmentfault.com/a/1190000011296839

 

問題四:setTimeout的執行?

setTimeout和Promise一樣也是異步的

 

宏任務一般包括:整體代碼script,setTimeout,setInterval。

 

微任務:Promise,process.nextTick

微任務執行優先級高於宏任務,所以Promise比setTimeout優先執行。

 

理解了以上4個問題,那么這道筆試題也就容易理解了

 

 

最終結果:

 

 

 

 

 

                       


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM