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

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

什麼是Async/Await?

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

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

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

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

問題四:setTimeout的執行?

setTimeoutPromise一樣也是異步的

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

微任務:Promise,process.nextTick

微任務執行優先級高於宏任務,所以PromisesetTimeout優先執行。

理解了以上4個問題,那麼這道筆試題也就容易理解了
在這裏插入圖片描述
最終結果:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章