今天羣裏討論一道題目,執行的結果是什麼html
console.log(1) setTimeout(() => {console.log(2)}) Promise.resolve().then(() => {console.log(3)}).then(() => {console.log(4)}) console.log(5)
結果是 15342
前端
以前只是明白JS事件循環的大概,今天想完全把它弄懂,查了一些資料,理了一下思路。node
由於Javascript是單線程運行的。爲何必須是單線程?由於在JavaScript誕生之初就是爲了在瀏覽器中運行操做DOM,若是是多線程,兩個線程同時操做一個DOM,那麼瀏覽器會灰常糾結,不知道該聽誰的。promise
單線程會有一個問題,就是順序執行,碰到耗時的任務,會一直等待下去,沒有效率。因此有了事件循環,把異步的任務添加到一個事件隊列中去,主進程繼續執行下面的代碼,等到異步任務處理完成,纔會通知主進程執行異步任務的回調,大大提升了效率。若是部署得好,JavaScript程序是不會出現堵塞的,這就是爲何NodeJS
平臺能夠用不多的資源,應付大流量訪問的緣由。瀏覽器
咱們都知道瀏覽器是多進程的(一個進程中能夠有多個線程,JavaScript是單線程的),其中有個進程對於咱們前端工程師來講是很熟悉的,那就是渲染進程,也叫瀏覽器內核。渲染進程包含了幾個進程,以下前端工程師
GUI渲染線程
(負責解析 HTML CSS 渲染成頁面)JS引擎線程
(負責執行JS代碼,也就是咱們常說的V8引擎)事件觸發線程
(也就是我理解的觸發事件隊列的,一些異步的操做(setInternal、setTimeout、異步請求等)完成後的回調都放在這裏,等待JS引擎線程執行完代碼後就開始執行這裏面的回調函數)定時觸發器線程
(用於setInternal與setTimeout的計時,時間到了,就會把他們的回調放入事件隊列中,等待JS主進程執行完代碼空閒時執行)異步http請求線程
(就是咱們常說的異步請求,完成後,也是把它的回調放入事件隊列)上面的代碼爲何會輸出 15342
呢,按道理來講,setTimeout
函數是異步,會把它放入事件隊列,繼續執行下面代碼,應該是 13452
,
這就要說一下在JS中,還有一種叫microtask
的東西,這個小東西是放在主任務執行完以後,事件隊列中的回調函數以前執行。Promise
就屬因而microtask
。多線程
也就是主任務開始執行,碰到異步任務的放入事件隊列中,繼續執行主任務,主任務執行結束,當即執行microtask
,而後執行事件隊列中的回調函數。異步
node中的事件循環和瀏覽器會有不一樣,看下面代碼,輸出結果是什麼socket
setTimeout(() => console.log(1)) setImmediate(() => console.log(2)) process.nextTick(() => console.log(3)) Promise.resolve().then(() => console.log(4)) ;(() => console.log(5))()
node官網上有對Event Loop
的介紹ide
這張圖中,node中事件循環包括六個階段,當主任務執行完以後,會依次進入這六個階段
timers
(處理setTimeout和setInterval的回調函數,主線程會檢查一下當前時間,是否知足定時器的條件。若是知足就執行回調函數,不然就離開這個階段。)I/O callbacks
(執行一些錯誤的回調和上輪應該在poll執行而沒有執行的回調)idle prepare
(這個階段只供 libuv 內部調用,咱們能夠先忽略)Poll
(等待還未返回的 I/O 事件,並執行回調,等待的過程當中若是有timer到時間,那就進入timer階段,若是有setImmediate,直接進入check階段)check
(該階段執行setImmediate()的回調函數)close callbacks
(該階段執行關閉請求的回調函數,好比socket.on('close', ...))上面代碼 setTimeout放入事件循環隊列中(雖然沒有設置延遲的時間,可是它是異步函數,仍是要放入事件循環隊列中),接着 setImmediate
也是要放入事件循環隊列,接着 process.nextTick
(它y優先於promise
執行,在主任務執行完當即會執行它),接着 Promise
(不用多說了,可是會在 process.nextTick
以後執行,優先級不如process.nextTick
高),接着是當即執行的同步函數,打印 5,緊接着執行 process.nextTick
,打印 3 ,緊接着執行 Promise,打印 4。
接下來就進入事件循環了,首先進入 timers
階段,檢查後發現已經到時間,執行回調,打印 1 ,而後是執行下面的階段,等到了check
階段,執行 setImmediate
的回調,打印 3 。
這只是一種狀況,還有不少種狀況能夠自行試一試。這樣就會對node的事件循環機制有更深的瞭解。
初步的認識,若有錯誤,還請指正~
https://funteas.com/topic/5a64e9482630e6f31583701d
http://www.ruanyifeng.com/blog/2018/02/node-event-loop.html
http://www.ruanyifeng.com/blog/2014/10/event-loop.html
https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/