摘要:知乎的問題也有何幻大神詳細的講解。我們之前說的異步任務隊列,指的是。每次拿到隊列上任務并執行之后,都會去檢查隊列,以此循環。主線程執行完畢則檢查隊列并執行,輸出和。以上是最新版本的中測試結果。
這部分內容源于知乎上的一個提問。
setTimeout(function(){console.log(4)},0); new Promise(function(resolve){ console.log(1) for( var i=0 ; i<10000 ; i++ ){ i==9999 && resolve() } console.log(2) }).then(function(){ console.log(5) }); console.log(3); // 1 // 2 // 3 // 5 // 4
之前我們說過then方法添加的回調函數都是異步執行的,所以按照我們正常的認知,結果應該是12345,因為4是先添加到異步隊列,而5在之后添加到異步隊列。
知乎的問題也有何幻大神詳細的講解。這里我就簡單的說一下吧。
我們都知道javascript是單線程的,也就是說,一個時間只能做一件事。所以,所有的任務都要按照一定的順序排隊,然后一個一個執行。如果所有的任務都是同步的,那就沒有什么問題,代碼按照從前到后的順序依次執行就可以了,但我們實際工作過程中,難免會有一些操作需要異步執行——比如事件,比如ajax,比如setTimeout。
所以,瀏覽器會維護一個任務隊列(task queue),任務隊列是先進先出的,也就是說,先進入任務隊列的會先執行。當主線程任務執行完畢,就會查看任務隊列中有沒有新任務,如果有,則把第一個任務放到主線程中執行,以此循環往復,這個過程也就是Event loops。
我之前也一直都以為瀏覽器中只有一個任務隊列,看到這個問題后才知道。原來瀏覽器中的任務隊列不止一個,且優先級也不同。基本上可以分為如下兩種:
macro-task: script(整體代碼), setTimeout, setInterval, setImmediate, I/O, UI rendering
micro-task: process.nextTick, 原生Promise, Object.observe, MutationObserver
我們看到原生Promise和setTimeout分別屬于micro-task和macro-task。我們之前說的異步任務隊列,指的是macro-task。而micro-task的執行順序,與之不同。
在執行完主線程上的所有任務時,會先去查看micro-task隊列中有沒有任務,如果有,則依次執行micro-task隊列中的所有任務,之后才去查看macro-task隊列。每次拿到macro-task隊列上任務并執行之后,都會去檢查micro-task隊列,以此循環。所以上面題目中結果是12354就很明了了。
我們看一個例子,并詳細解釋它的執行流程。
console.log("script1"); setTimeout(function() { console.log("setTimeout1"); }, 300); Promise.resolve().then(function() { console.log("promise1"); }).then(function() { console.log("promise2"); }); console.log("script2"); setTimeout(function() { console.log("setTimeout2"); Promise.resolve().then(function() { console.log("promise3"); }) }, 0); // script1 // script2 // promise1 // promise2 // setTimeout2 // promise3 // setTimeout1
結果如代碼中注釋所示。具體執行步驟如下:
①代碼從上到下執行,先打印出script1。
②執行到第一個setTimeout時,發現300ms后把函數添加到macro-task隊列中。
③執行Promise時,依次把輸出promise1和promise2的任務添加到micro-task隊列。
④打印script2。
⑤執行第二個setTimeout時因為設置的是0ms,所以立即(其實瀏覽器有最少4ms的限制)添加到macro-task隊列中。
⑥主線程執行完畢則檢查micro-task隊列并執行,輸出promise1和promise2。
⑦然后檢查macro-task隊列,輸出setTimeout2,并把輸出promise3的任務添加到micro-task隊列。
⑧再次檢查micro-task隊列并執行,輸出promise3。
⑨最后檢查macro-task隊列,輸出setTimeout1,因為它是300ms后添加到macro-task隊列,所以后輸出。
規范中的流程是這個樣子,但是不同的瀏覽器中,實際輸出的結果可能會不相同。以上是最新版本的chrome中測試結果。
最后,推薦一篇外國友人的博客,我就是看了這篇文章才完全弄清楚的,里面內容講的特別詳細。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/86680.html
摘要:內部總體上分為兩種情況,一種是當前對象狀態已經變為或,此時則直接把響應的回調函數添加到異步隊列中,另一種情況是當前對象狀態還是,此時則把響應的回調函數依次添加到數組中。 今天,我帶著大家一步一步跟著規范實現一個自己的Promise,大家可以對照我的第二篇文章Promise介紹--規范篇或官方規范來一一學習。 Promise內部有三個固定的狀態,我們在文件中提前定義。 const PEN...
摘要:的翻譯文檔由的維護很多人說,阮老師已經有一本關于的書了入門,覺得看看這本書就足夠了。前端的異步解決方案之和異步編程模式在前端開發過程中,顯得越來越重要。為了讓編程更美好,我們就需要引入來降低異步編程的復雜性。 JavaScript Promise 迷你書(中文版) 超詳細介紹promise的gitbook,看完再不會promise...... 本書的目的是以目前還在制定中的ECMASc...
摘要:規范中對于構造函數沒有明確說明,所以在此處拿出來講解一下。構造函數只接收一個參數,且該參數必須是一個函數,任何其他的值比如等都會報一個的錯誤。 本篇文章是Promise系列文章的第二篇,主要是講解基于Promise/A+規范,在傳入不同類型的參數時,promise內部分別會如何處理。本章的主要目的是讓大家對promise有一個更加深入的理解,也為下一篇講如何實現一個promise庫做準...
摘要:請求的傳統寫法改為后的寫法很顯然,我們把異步中使用回調函數的場景改為了等函數鏈式調用的方式。數組中第一個元素是異步的,第二個是非異步,會立即改變狀態,所以新對象會立即改變狀態并把傳遞給成功時的回調函數。 前言 Promise,相信每一個前端工程師都或多或少地在項目中都是用過,畢竟它早已不是一個新名詞。ES6中已經原生對它加以支持,在caniuse中搜索一下Promise,發現新版的ch...
摘要:而之后,我們得到的是一個是一個對象,我們可以使用語句定義回調函數,函數的內容呢,則是將讀取到的返回給并繼續讓從斷點處執行。 在上一篇中我們梳理了koa當中中間件的洋蔥模型執行原理,并實現了一個可以讓洋蔥模型自動跑起來的流程管理函數。這一篇,我們再來研究一下koa當中異步回調同步化寫法的原理,同樣的,我們也會實現一個管理函數,是的我們能夠通過同步化的寫法來寫異步回調函數。 1. 回調金字...
閱讀 3522·2021-10-08 10:04
閱讀 869·2019-08-30 15:54
閱讀 2185·2019-08-29 16:09
閱讀 1352·2019-08-29 15:41
閱讀 2279·2019-08-29 11:01
閱讀 1740·2019-08-26 13:51
閱讀 1030·2019-08-26 13:25
閱讀 1814·2019-08-26 13:24