摘要:比如下面一個例子例輸出為先輸出,沒有問題,因為是同步任務在主線程中優先執行,這里的問題是和任務的執行優先級是如何定義的。
在原文的基礎上加了一點參考資料問題的引出
event loop都不陌生,是指主線程從“任務隊列”中循環讀取任務,比如
例1:
setTimeout(function(){console.log(1)},0); console.log(2) //輸出2,1
在上述的例子中,我們明白首先執行主線程中的同步任務,當主線程任務執行完畢后,再從event loop中讀取任務,因此先輸出2,再輸出1。
event loop讀取任務的先后順序,取決于任務隊列(Job queue)中對于不同任務讀取規則的限定。比如下面一個例子:
例2:
setTimeout(function () { console.log(3); }, 0); Promise.resolve().then(function () { console.log(2); }); console.log(1); //輸出為 1 2 3
先輸出1,沒有問題,因為是同步任務在主線程中優先執行,這里的問題是setTimeout和Promise.then任務的執行優先級是如何定義的。
2 . Job queue中的執行順序
在Job queue中的隊列分為兩種類型:macro-task和microTask。我們舉例來看執行順序的規定,我們設
macro-task隊列包含任務: a1, a2 , a3
micro-task隊列包含任務: b1, b2 , b3
執行順序為,首先執行marco-task隊列開頭的任務,也就是 a1 任務,執行完畢后,在執行micro-task隊列里的所有任務,也就是依次執行b1, b2 , b3,執行完后清空micro-task中的任務,接著執行marco-task中的第二個任務,依次循環。
了解完了macro-task和micro-task兩種隊列的執行順序之后,我們接著來看,真實場景下這兩種類型的隊列里真正包含的任務(我們以node V8引擎為例),在node V8中,這兩種類型的真實任務順序如下所示:
macro-task隊列真實包含任務:
script(主程序代碼),setTimeout, setInterval, setImmediate, I/O, UI rendering
micro-task隊列真實包含任務:
process.nextTick, Promises, Object.observe, MutationObserver
由此我們得到的執行順序應該為:
script(主程序代碼)—>process.nextTick—>Promises...——>setTimeout——>setInterval——>setImmediate——> I/O——>UI rendering
在ES6中macro-task隊列又稱為ScriptJobs,而micro-task又稱PromiseJobs
3 . 真實環境中執行順序的舉例
(1) setTimeout和promise
例3:
setTimeout(function () {
console.log(3);
}, 0);
Promise.resolve().then(function () {
console.log(2);
});
console.log(1);
我們先以第1小節的例子為例,這里遵循的順序為:
script(主程序代碼)——>promise——>setTimeout
對應的輸出依次為:1 ——>2————>3
(2) process.nextTick和promise、setTimeout
例子4:
setTimeout(function(){console.log(1)},0); new Promise(function(resolve,reject){ console.log(2); resolve(); }).then(function(){console.log(3) }).then(function(){console.log(4)}); process.nextTick(function(){console.log(5)}); console.log(6); //輸出2,6,5,3,4,1
這個例子就比較復雜了,這里要注意的一點在定義promise的時候,promise構造部分是同步執行的,這樣問題就迎刃而解了。
首先分析Job queue的執行順序:
script(主程序代碼)——>process.nextTick——>promise——>setTimeout
I) 主體部分: 定義promise的構造部分是同步的,
因此先輸出2 ,主體部分再輸出6(同步情況下,就是嚴格按照定義的先后順序)
II)process.nextTick: 輸出5
III)promise: 這里的promise部分,嚴格的說其實是promise.then部分,輸出的是3,4
IV) setTimeout : 最后輸出1
綜合的執行順序就是: 2——>6——>5——>3——>4——>1
(3)更復雜的例子
setTimeout(function(){console.log(1)},0); new Promise(function(resolve,reject){ console.log(2); setTimeout(function(){resolve()},0) }).then(function(){console.log(3) }).then(function(){console.log(4)}); process.nextTick(function(){console.log(5)}); console.log(6); //輸出的是 2 6 5 1 3 4
這種情況跟我們(2)中的例子,區別在于promise的構造中,沒有同步的resolve,因此promise.then在當前的執行隊列中是不存在的,只有promise從pending轉移到resolve,才會有then方法,而這個resolve是在一個setTimout時間中完成的,因此3,4最后輸出。
知識點參考:
process.nextTick(callback)
process.nextTick()方法將 callback 添加到"next tick 隊列"。 一旦當前事件輪詢隊列的任務全部完成,在next tick隊列中的所有callbacks會被依次調用。
這種方式不是setTimeout(fn, 0)的別名。它更加有效率。事件輪詢隨后的ticks 調用,會在任何I/O事件(包括定時器)之前運行。
每次事件輪詢后,在額外的I/O執行前,next tick隊列都會優先執行。 遞歸調用nextTick callbacks 會阻塞任何I/O操作,就像一個while(true) 循環一樣。
function definitelyAsync(arg, cb) { if (arg) { process.nextTick(cb); return; } fs.stat("file", cb); //涉及io操作 } //這里process.nextTick就會阻塞io操作
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/96611.html
摘要:簡要介紹談談在隊列中的執行順序問題的來源都不陌生,是指主線程從任務隊列中循環讀取任務,比如例輸出在上述的例子中,我們明白首先執行主線程中的同步任務,當主線程任務執行完畢后,再從中讀取任務,因此先輸出,再輸出。 簡要介紹:談談promise.resove,setTimeout,setImmediate,process.nextTick在EvenLoop隊列中的執行順序 問題的來源 eve...
摘要:二瀏覽器端在講解事件循環之前先談談中同步代碼異步代碼的執行流程。三端我自己認為的事件循環和瀏覽器端還是有點區別的,它的事件循環依靠引擎。四總結本篇主要介紹了瀏覽器和對于事件循環機制實現,由于能力水平有限,其中可能有誤之處歡迎指出。 一、前言 前幾天聽公司一個公司三年的前端說今天又學到了一個知識點-微任務、宏任務,我問他這是什么東西,由于在吃飯他淺淺的說了下,當時沒太理解就私下學習整理一...
摘要:事件完成,回調函數進入。我們來分析一段較復雜的代碼,看看你是否真的掌握了的執行機制第一輪事件循環流程分析如下整體作為第一個宏任務進入主線程,遇到,輸出。宏任務微任務第三輪事件循環宏任務執行結束,執行兩個微任務和。 關于JavaScript 首先js是單線程的,執行任務肯定是一個接著一個。在最新的html5中提出了web-worker,但是JavaScript是單線程這一核心沒有改變,一...
摘要:換句話說當一個異步過程調用發出后,調用者不會立刻得到結果,而是調用發出后,被調用者通過狀態通知或回調函數處理這個調用。 JavaScript單線程機制 JavaScript的一個語言特性(也是這門語言的核心)就是單線程。什么是單線程呢?簡單地說就是同一時間只能做一件事,當有多個任務時,只能按照一個順序一個完成了再執行下一個 為什么JS是單線程的呢? JS最初被設計用在瀏覽器中,作為...
摘要:瀏覽器與的異同,以及部分機制有人對部分迷惑,本身構造函數是同步的,是異步。瀏覽器的的已全部分析完成,過程中引用阮一峰博客,知乎,部分文章內容,侵刪。 瀏覽器與NodeJS的EventLoop異同,以及部分機制 PS:有人對promise部分迷惑,Promise本身構造函數是同步的,.then是異步。---- 2018/7/6 22:35修改 javascript 是一門單線程的腳本...
閱讀 2171·2020-06-12 14:26
閱讀 2477·2019-08-29 16:41
閱讀 1885·2019-08-29 15:28
閱讀 2448·2019-08-26 13:43
閱讀 753·2019-08-26 13:37
閱讀 2773·2019-08-23 18:13
閱讀 2791·2019-08-23 15:31
閱讀 1014·2019-08-23 14:10