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運行機制是什麼?ajax

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

總結幾點就是:segmentfault

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

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

古人云:「君子一言既出;駟馬難追」,這種「承諾未來會執行」的對象在JavaScript中稱爲Promise對象。異步

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

參考:http://www.javashuo.com/article/p-fydjigyf-ca.htmlide

這裏擴展一個問題:什麼是異步呢?異步編程

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

js代碼只能一行一行的執行,不能在同一時間執行多個js代碼任務,這就致使若是有一段耗時較長的計算,或者是一個ajax請求等IO操做,若是沒有異步的存在,就會出現用戶長時間等待,而且因爲當前任務還未完成,因此這時候全部的其餘操做都會無響應,這時候就須要異步任務。

參考:http://www.javashuo.com/article/p-wkwacora-du.html

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隊列。

參考:http://www.javashuo.com/article/p-pqnsofgj-ek.html

問題四:setTimeout的執行?

setTimeout和Promise同樣也是異步的

宏任務通常包括:總體代碼script,setTimeout,setInterval。

微任務:Promise,process.nextTick

微任務執行優先級高於宏任務,因此Promise比setTimeout優先執行。
理解了以上4個問題,那麼這道筆試題也就容易理解了

最終結果:

相關文章
相關標籤/搜索