摘要:是這樣描述的函數中可能會有表達式,這會使函數暫停執行,等待表達式中的解析完成后繼續執行函數并返回解決結果。返回值返回對象的處理結果。當執行到時,這個任務會被放入到回調隊列中,等待調用棧有空閑時事件循環再來取走它。
原文地址:https://lvdingjin.github.io/tech/2018/05/27/async-and-await.html
故事要從一道今日頭條的筆試題說起~
題目來源:半年工作經驗今日頭條和美團面試題面經分享?。。。?!
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")
求打印結果是什么?
相信是個前端都知道啦,這道題目考的就是js里面的事件循環和回調隊列咯~
今天題主假設看客都已經了解了setTimeout是宏任務會在最后執行的前提(因為它不是今天要討論的重點),我們主要來講講promise、async和await之間的關系。
先上正確答案:
script start async1 start async2 promise1 script end promise2 async1 end setTimeout
事實上,沒有在控制臺執行打印之前,我覺得它應該是這樣輸出的:
script start async1 start async2 async1 end promise1 script end promise2 setTimeout
為什么這樣認為呢?因為我們(粗淺地)知道await之后的語句會等await表達式中的函數執行完得到結果后,才會繼續執行。
MDN是這樣描述await的:
async 函數中可能會有 await 表達式,這會使 async 函數暫停執行,等待表達式中的 Promise 解析完成后繼續執行 async 函數并返回解決結果。
會認為輸出結果是以上的樣子,是因為沒有真正理解這句話的含義。
阮一峰老師的解釋我覺得更容易理解:
async 函數返回一個 Promise 對象,當函數執行的時候,一旦遇到 await 就會先返回,等到觸發的異步操作完成,再接著執行函數體內后面的語句。
對啦就是這樣,MDN描述的暫停執行,實際上是讓出了線程(跳出async函數體)然后繼續執行后面的腳本的。這樣一來我們就明白了,所以我們再看看上面那道題,按照這樣描述那么他的輸出結果就應該是:
script start async1 start async2 promise1 script end async1 end promise2 setTimeout
好像哪里不太對?對比控制臺輸出的正確結果,咦~有兩句輸出是不一樣的呀??!
async1 end promise2
為什么會這樣呢?這也是這道題目最難理解的一個地方。要搞明白這個事情,我們需要先來回顧一些概念:
asyncasync function 聲明將定義一個返回 AsyncFunction 對象的異步函數。當調用一個 async 函數時,會返回一個 Promise 對象。當這個 async 函數返回一個值時,Promise 的 resolve 方法會負責傳遞這個值;當 async 函數拋出異常時,Promise 的 reject 方法也會傳遞這個異常值。
所以你現在知道咯,使用 async 定義的函數,當它被調用時,它返回的其實是一個Promise對象。
我們再來看看 await 表達式執行會返回什么值。
語法:[return_value] = await expression;表達式(express):一個 Promise 對象或者任何要等待的值。
返回值(return_value):返回 Promise 對象的處理結果。如果等待的不是 Promise 對象,則返回該值本身。
所以,當await操作符后面的表達式是一個Promise的時候,它的返回值,實際上就是Promise的回調函數resolve的參數。
明白了這兩個事情后,我還要再啰嗦兩句。我們都知道Promise是一個立即執行函數,但是他的成功(或失?。簉eject)的回調函數resolve卻是一個異步執行的回調。當執行到resolve()時,這個任務會被放入到回調隊列中,等待調用棧有空閑時事件循環再來取走它。
終于進入正文:解題好了鋪墊完這些概念,我們回過頭看上面那道題目困惑的那兩句關鍵的地方(建議一邊對著題目一邊看解析我怕我講的太快你跟不上啊哈哈
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/95331.html
摘要:不再廢話,下面見題執行執行輸出結果執行執行這道題最難理解的地方和的執行順序,前面的結果一般沒有異議,如果不明白,百度一下變可以理解。 先指明這道題是面試題的改版,原題可以看:promise、async和await之執行順序的那點事這道題也不是我改的,出處見:async/await 執行順序詳解 這兩篇文章寫的非常好,我仔細琢磨了一下,感覺受益匪淺,決定記錄一下自己的理解。不再廢話,下面...
摘要:下面開始分析開頭的代碼第一輪事件循環流程整體作為第一個宏任務進入主線程,遇到,輸出遇到函數聲明,聲明暫時不用管遇到,其回調函數被分發到微任務中。我們記為遇到,其回調函數被分發到宏任務中。 先上一道常見的筆試題 console.log(1); async function async1() { console.log(2); await async2(); con...
摘要:通過來對數據進行轉化處理或最終暴露給調用者對異常的處理。封裝在實際開發中,的都是相同的,不同的是請求的方法名與參數。上述提到的與的請求時機。下面來看下完整的封裝。 每一門語言都離不開網絡請求,有自己的一套Networking Api。React Native使用的是Fetch。 今天我們來談談與Fetch相關的一些事情。 purpose 通過這篇文章,你將了解到以下幾點關于Fet...
摘要:函數節流背景中的函數大多數情況下都是由用戶主動調用觸發的除非是函數本身的實現不合理否則一般不會遇到跟性能相關的問題但在少數情況下函數的觸發不是由用戶直接控制的在這些場景下函數可能被非常頻繁調用而造成大的性能問題場景事件事件滾動事件共同的特征 函數節流 背景 javascript中的函數大多數情況下都是由用戶主動調用觸發的, 除非是函數本身的實現不合理, 否則一般不會遇到跟性能相關的問題...
閱讀 2969·2021-11-25 09:43
閱讀 3586·2021-11-24 11:13
閱讀 3354·2021-10-14 09:42
閱讀 2556·2021-09-23 11:53
閱讀 3605·2021-09-22 15:57
閱讀 3221·2021-09-02 09:54
閱讀 3499·2019-08-30 13:47
閱讀 1638·2019-08-29 16:55