JS 會建立一個相似於 while (true) 的循環,每執行一次循環體的過程稱之爲 Tick。每次 Tick 的過程就是查看是否有待處理事件,若是有則取出相關事件及回調函數放入執行棧中由主線程執行。待處理的事件會存儲在一個任務隊列中,也就是每次 Tick 會查看任務隊列中是否有須要執行的任務。javascript
異步操做會將相關回調添加到任務隊列中。而不一樣的異步操做添加到任務隊列的時機也不一樣,如 onclick, setTimeout, ajax 處理的方式都不一樣,這些異步操做是由瀏覽器內核的 webcore 來執行的,webcore 包含上圖中的3種 webAPI,分別是 DOM Binding、network、timer模塊。java
1. onclick 由瀏覽器內核的 DOM Binding 模塊來處理,當事件觸發的時候,回調函數會當即添加到任務隊列中。node
2. setTimeout 會由瀏覽器內核的 timer 模塊來進行延時處理,當時間到達的時候,纔會將回調函數添加到任務隊列中。web
3. ajax 則會由瀏覽器內核的 network 模塊來處理,在網絡請求完成返回以後,纔將回調添加到任務隊列中。面試
任務隊列是在事件循環之上的,事件循環每次 tick 後會查看 ES6 的任務隊列中是否有任務要執行,也就是 ES6 的任務隊列比事件循環中的任務(事件)隊列優先級更高。如 Promise 就使用了 ES6 的任務隊列特性。ajax
瀏覽器的內核是多線程的,它們在內核控制下相互配合以保持同步,一個瀏覽器至少實現三個常駐線程:JavaScript引擎線程,GUI渲染線程,瀏覽器事件觸發線程。數據庫
優勢:一、將耗時較長的操做(網絡請求、圖片下載、音頻下載、數據庫訪問等)放在子線程中執行,能夠防止主線程的卡死;二、能夠發揮多核處理的優點,提高cpu的使用率。 缺點:一、每開闢一個子線程就消耗必定的資源; 二、會形成代碼的可讀性變差;三、若是出現多個線程同時訪問一個資源,會出現資源爭奪的狀況。promise
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始終都是單線程的,先執行的確定是同步任務,再根據進入任務隊列的順序先進先出,先微後宏。 微任務是一次性將隊列中存在的微任務執行完畢,宏任務是一個一個先進先出。 Promise是一個構造函數,調用的時候會生成Promise實例。當Promise的狀態改變時會調用then函數中定義的回調函數。 咱們都知道這個回調函數不會馬上執行,他是一個微任務會被添加到當前任務隊列中的末尾,在下一輪任務開始執行以前執行。 async/await成對出現,async標記的函數會返回一個Promise對象,可使用then方法添加回調函數。await後面的語句會同步執行。但 await 下面的語句會被當成微任務添加到當前任務隊列的末尾異步執行。 */
/* 答案: > node8版本: script start -> async1 start -> async2 -> promise1 -> script end -> promise2 -> async1 end -> setTimeout <= node8版本: script start -> async1 start -> async2 -> promise1 -> script end -> async1 end -> promise2 -> setTimeout 這主要是node.js8版本與其餘版本的差別,他們對await的執行方法不一樣 */
複製代碼