摘要:一篇文章和一道面試題最近,有篇名為張圖幫你一步步看清和的執行順序的文章引起了我的關注。作者用一道年今日頭條的前端面試題為引子,分步講解了最終結果的執行原因。從字面意思理解,讓我們等等。當前的最新版本,在這里的執行順序上,的確存在有問題。
一篇文章和一道面試題
最近,有篇名為 《8張圖幫你一步步看清 async/await 和 promise 的執行順序》 的文章引起了我的關注。
作者用一道2017年「今日頭條」的前端面試題為引子,分步講解了最終結果的執行原因。其中涉及到了不少概念,比如異步的執行順序,宏任務,微任務等等,同時作者限定了執行范圍,以瀏覽器的 event loop 機制為準。下面是原題的代碼:
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");
緊接著,作者先給出了答案。并希望讀者先行自我測試。
script start async1 start async2 promise1 script end promise2 async1 end setTimeout
我在看這道題的時候,先按照自己的理解寫出了結果。
script start async1 start async2 promise1 script end async1 end promise2 setTimeout一些重要的概念
這里需要先簡單地說一些 event loop 的概念。
Javascript是單線程的,所有的同步任務都會在主線程中執行。
主線程之外,還有一個任務隊列。每當一個異步任務有結果了,就往任務隊列里塞一個事件。
當主線程中的任務,都執行完之后,系統會 “依次” 讀取任務隊列里的事件。與之相對應的異步任務進入主線程,開始執行。
異步任務之間,會存在差異,所以它們執行的優先級也會有區別。大致分為 微任務(micro task,如:Promise、MutaionObserver等)和宏任務(macro task,如:setTimeout、setInterval、I/O等)。同一次事件循環中,微任務永遠在宏任務之前執行。
主線程會不斷重復上面的步驟,直到執行完所有任務。
另外,還有 async/await 的概念。
async 函數,可以理解為是Generator 函數的語法糖。
它建立在promise之上,總是與await一起使用的。
await會返回一個Promise 對象,或者一個表達式的值。
其目的是為了讓異步操作更優雅,能像同步一樣地書寫。
我的理解再說說我對這道題的理解。
首先,從console的數量上看,會輸出8行結果。
再瞟了一眼代碼,看到了setTimeout,于是,默默地把它填入第8行。
在setTimeout附近,看到了 console.log( "script start" ) 和 async1(),可以確認它們是同步任務,會先在主線程中執行。所以,妥妥地在第1行填入 script start,第2行填入async1方法中的第一行 async1 start。
接下來,遇到了await。從字面意思理解,讓我們等等。需要等待async2()函數的返回,同時會阻塞后面的代碼。所以,第3行填入 async2。
講道理,await都執行完了,該輪到console.log( "async1 end" )的輸出了。但是,別忘了下面還有個Promise,有一點需要注意的是:當 new 一個 Promise的時候,其 resolve 方法中的代碼會立即執行。如果不是 async1()的 await 橫插一杠,promise1 可以排得更前面。所以,現在第4行填入 promise1。
再接下來,同步任務 console.log( "script end" ) 執行。第5行填入 script end。
還有第6和第7行,未填。回顧一下上面提到 async/await 的概念,其目的是為了讓異步能像同步一樣地書寫。那么,我認為 console.log( "async1 end" ) 就是個同步任務。所以,第6行填入async1 end。
最后,順理成章地在第7行填入 promise2。
與作者答案的不同回過頭對比與作者的答案,發現第6和第7行的順序有問題。
再耐心地往下看文章,反復地看了幾遍 async1 end 和 promise2 誰先誰后,還是無法理解為何在chrome瀏覽器中,promise2 會先于 async1 end 輸出。
然后,看到評論區,發現也有人提出了相同的疑惑。@rhinel提出,在他的72.0.3622.0(正式版本)dev(64 位)的chrome中,跑出來的結果是 async1 end 在 promise2 之前。
隨即我想到了一種可能,JS的規范可能會在未來有變化。于是,我用自己的react工程試了一下(工程中的babel-loader版本為7.1.5。.babelrc的presets設置了stage-3),結果與我的理解一致。當前的最新版本 chromeV71,在這里的執行順序上,的確存在有問題。
于是,我也在評論區給作者留了言,進行了討論。@rhinel最后也證實,其實最近才發布通過了這個順序的改進方案,這篇 《Faster async functions and promises》 詳細解釋了這個改進,以及實現效果。不久之后,作者也在他文章的最后,補充了我們討論的結果,供讀者參考。
總結最后,我想說的是,本文雖然只是由一道面試題引申出的,對瀏覽器執行順序的思考、討論與驗證的過程。但正是因為有了這些過程,才讓更多的思想得以碰撞,概念進一步得以理解,規范得以明了。
有機會的話,希望能有與更多的同道,多多交流。
更新講道理,async/await 已經出來挺久了,但在近期的面試中,凡是問及異步操作,面試者的回答都還是 Promise,甚至知道 async/await 都很少,看來還有待進一步普及。并不是說 Promise 有什么不好,只是覺得 async/await 用著挺爽的,希望能有更多的人用吧。只有用了,才能進一步理解,產生更多的思考。
所以,這兩天翻出了之前寫的關于什么是async函數,及其相較于 Promise 的優勢。重新整理了一下,原文請前往《細說async/await相較于Promise的優勢》。
希望對你有幫助,也期待進一步的交流,感謝!
PS:歡迎關注我的公眾號 “超哥前端小棧”,交流更多的想法與技術。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/100308.html
摘要:正如我標題所說,簡歷被拒。看了我簡歷之后說頭條競爭激烈,我背景不夠,點到為止。。三準備面試其實從三月份投遞簡歷開始準備面試到四月份收,也不過個月的時間,但這都是建立在我過去一年的積累啊。 本文是 無精瘋 同學投稿的面試經歷 關注微信公眾號:進擊的java程序員K,即可獲取最新BAT面試資料一份 在此感謝 無精瘋 同學的分享 目錄: 印象中的頭條 面試背景 準備面試 ...
摘要:正如我標題所說,簡歷被拒。看了我簡歷之后說頭條競爭激烈,我背景不夠,點到為止。。三準備面試其實從三月份投遞簡歷開始準備面試到四月份收,也不過個月的時間,但這都是建立在我過去一年的積累啊。 本文是 無精瘋 同學投稿的面試經歷 關注微信公眾號:進擊的java程序員K,即可獲取最新BAT面試資料一份 在此感謝 無精瘋 同學的分享目錄:印象中的頭條面試背景準備面試頭條一面(Java+項目)頭條...
摘要:在這里,如果用箭頭函數,可以這樣改寫箭頭函數并沒有自己的,所以事件處理函數的調用者并不受影響。比如,在需要動態上下文的場景中,使用箭頭函數需要格外地小心,這些場景包括對象的方法原型方法事件的回調構造函數。 showImg(https://segmentfault.com/img/bVboce6?w=1304&h=734); 前言 年味兒漸散,收拾下心情,繼續敲代碼吧。 對于即將到來金三...
摘要:問題的關鍵在于其執行過程中的微任務數量,下文中我們需要用上述代碼中的方式對微任務的執行順序進行標記,以輔助我們理解這其中的執行過程。 原文發布在掘金社區:https://juejin.im/post/5c3cc981f265da616a47e028 起源 2019年了,相信大家對 Promise 和 async/await 都不再陌生了。 前幾日,我在社區讀到了一篇關于 async/...
摘要:但是有一個總的原則那就是總會指向,調用函數的那個對象。作為對象方法的調用函數作為某個對象的方法調用,這時就指這個上級對象。 showImg(https://segmentfault.com/img/bVbnvF7?w=750&h=422); 這是前端面試題系列的第 4 篇,你可能錯過了前面的篇章,可以在這里找到: 偽類與偽元素的區別及實戰 如何實現一個圣杯布局? 今日頭條 面試題和思...
閱讀 3208·2021-09-30 09:48
閱讀 3485·2021-09-22 16:00
閱讀 1062·2019-08-30 13:08
閱讀 3098·2019-08-30 10:53
閱讀 2410·2019-08-29 18:33
閱讀 1583·2019-08-29 12:47
閱讀 896·2019-08-29 12:16
閱讀 1929·2019-08-26 12:02