依然是:經濟基礎決定上層建築。javascript
先解釋現代js引擎幾個概念。html
爲了方便描述與理解,做出如下約定:html5
js 是一門單線程語言。 js 引擎有一個主線程(main thread)用來解釋和執行 js 程序,實際上還存在其餘的線程。例如:處理AJAX請求的線程、處理DOM事件的線程、定時器線程、讀寫文件的線程(例如在node.js中)等等。這些線程可能存在於 js 引擎以內,也可能存在於 js 引擎以外,在此咱們不作區分。不妨叫它們工做線程。可是前輩們很有一種小本本記好的說法,那就是,要相信 js 單線程的本質,其餘一切看似多線程,都是紙老虎。哈哈哈哈哈哈哈哈哈哈哈哈哈......java
任務分爲同步任務(synchronous)和異步任務(asynchronous),若是全部任務都由主線程來處理,會出現主線程被阻塞而使得頁面「假死」。爲了主線程不被阻塞,異步任務(如:AJAX異步請求,定時器等)就會交給工做線程來處理,異步任務完成後將異步回調函數註冊進任務隊列,等待主線程空閒時調用。流程如圖:node
// example console.log('example-start') setTimeout(() => { console.log('setTimeout-0') }, 0) console.log('example-end') /* chrome result * example-start example-end setTimeout-0 * */
上面一個簡單的小 js 片斷的執行過程:git
最後借用Philip Roberts的生動形象的一張圖,callback queue能夠簡單理解爲任務隊列,詳細的下面會講。github
然而Event Loop並無上面圖中描述那麼簡單。心塞塞 : (web
根據規範,事件循環是經過任務隊列的機制來進行協調的。一個 Event Loop 中,能夠有一個或者多個任務隊列(task queue),一個任務隊列即是一系列有序任務(task)的集合;每一個任務都有一個任務源(task source),源自同一個任務源的 task 必須放到同一個任務隊列,從不一樣源來的則被添加到不一樣隊列。chrome
setTimeout/Promise 等API即是任務源,而進入任務隊列的是他們指定的具體執行任務(回調函數)。來自不一樣任務源的任務會進入到不一樣的任務隊列。其中setTimeout與setInterval是同源的。vim
仔細查閱規範可知,異步任務可分爲 task(部分文章也稱爲 macro-task) 和 micro-task 兩類,不一樣的API註冊的異步任務會依次進入自身對應的隊列中,而後等待 Event Loop 將它們依次壓入執行棧中執行。
在事件循環中,每進行一次循環操做稱爲 tick,每一次 tick 的任務處理模型是比較複雜的,但關鍵步驟以下:
一個事件循環(Event Loop)中,主線程從任務隊列中取出一個任務 task 執行時,而這個正在執行的任務就是從 task queue(部分文章也稱爲 macro-task queue)中來的。當這個 task 執行結束後,js 會將 micro-task queue中全部 micro-task 都在同一個 Event Loop 中執行,當這些 micro-task 執行結束後還能繼續添加 micro-task 一直到整個 micro-task 隊列執行結束。而後當前本輪的 Event Loop 結束,主線程能夠繼續取下一個 task 執行。因此更詳細的 Event Loop 的流程圖以下:
// example console.log('example-start') setTimeout(() => { console.log('setTimeout-0') // setTimeout-1 }, 0) new Promise((resolve, reject) => { console.log('promise-1') resolve('promise-2') Promise.resolve().then(() => console.log('promise-3')) // then-1 }).then((response) => { // then-2 console.log(response) setTimeout(() => { console.log('setTimeout-10') // setTimeout-2 }, 10) }) console.log('example-end') /* chrome result * example-start promise-1 example-end promise-3 promise-2 setTimeout-0 setTimeout-10 * */
上面一個簡單的 js 片斷的執行過程:
若是上文理解有誤或者有疑惑,歡迎交流。
好記性不如爛筆頭。