什麼是單線程javascript
主程序只有一個線程,即同一時間片段內其只能執行單個任務。html
爲何選擇單線程?java
JavaScript的主要用途是與用戶互動,以及操做DOM。這決定了它只能是單線程,不然會帶來很複雜的同步問題。git
單線程意味着什麼?github
單線程就意味着,全部任務都須要排隊,前一個任務結束,纔會執行後一個任務。若是前一個任務耗時很長,後一個任務就須要一直等着。這就會致使IO操做(耗時但cpu閒置)
時形成性能浪費的問題。promise
如何解決單線程帶來的性能問題?瀏覽器
答案是異步!主線程徹底能夠無論IO操做,暫時掛起處於等待中的任務,先運行排在後面的任務。等到IO操做返回告終果,再回過頭,把掛起的任務繼續執行下去。因而,全部任務能夠分紅兩種,一種是同步任務(synchronous),另外一種是異步任務(asynchronous)網絡
注: 當主線程阻塞時,任務隊列仍然是可以被推入任務的併發
JavaScript 內存模型異步
講事件循環以前,先看一張下網上看到的 JavaScript 內存模型,相信看完這個會對事件循環機制有一種豁然開朗的感受。
JavaScript 代碼執行機制:
Event Loop
如今咱們來聊事件循環。事件循環顧名思義它就是一個循環,主線程會不斷循環執行上面的第三步,其基本的代碼邏輯以下所示:
while (queue.waitForMessage()) { queue.processNextMessage(); }
常見異步任務進入任務隊列時機
行爲 | 時機 |
---|---|
DOM操做 | 在用戶點擊等操做事件完成後 |
網絡操做(Ajax等) | 在網絡操做響應後 |
定時器 | 在規定時間到達後 |
事件循環機制圖解:
MacroTask(Task)
setTimeout, setInterval, setImmediate, requestAnimationFrame, I/O, UI rendering
MicroTask(在ES2015規範中稱爲Job)
process.nextTick, Promise, Object.observe, MutationObserver
規範:
注: event loop的每一個turn,是由瀏覽器決定先執行哪一個task queue。這容許瀏覽器爲不一樣的task source設置不一樣的優先級,好比爲用戶交互設置更高優先級來使用戶感受流暢。
function ELoop() { // 當前任務 let p = new Promise((resolve, reject)=>{ console.log("current Task") resolve(); }); let nextP; setTimeout(()=>{ console.log("MacroTask_1"); nextP.then(()=>{ // 第一次執行時,這段代碼並無執行到。 console.log("MicroTask_promise_1"); //第一個MicroTask }) console.log("MacroTask_1 end") }, 0) // 第一個 MacroTask setTimeout(()=>{ console.log("MacroTask_2"); console.log("MacroTask_2 end") }, 0)// 第二個MacroTask nextP = p.then(()=>{ console.log("MicroTask_promise_2"); //第一個MicroTask console.log(1) }).then(()=>{ console.log("MicroTask_promise_3"); // 第二個MicroTask console.log(1) }) console.log("current Task end") } ELoop(); /**輸出結果: current Task MicroTask_promise_2 MicroTask_promise_3 MacroTask_1 MicroTask_promise_1 MacroTask_2 **/
參考文獻:
從Promise來看JavaScript中的Event Loop、Tasks和Microtasks