成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

JS異步詳解 - 瀏覽器/Node/事件循環(huán)/消息隊列/宏任務(wù)/微任務(wù)

awesome23 / 1758人閱讀

js異步歷史

一個 JavaScript 引擎會常駐于內(nèi)存中,它等待著我們把JavaScript 代碼或者函數(shù)傳遞給它執(zhí)行

在 ES3 和更早的版本中,JavaScript 本身還沒有異步執(zhí)行代碼的能力,引擎就把代碼直接順次執(zhí)行了,異步任務(wù)都是宿主環(huán)境(瀏覽器)發(fā)起的(setTimeout、AJAX等)。

在 ES5 之后,JavaScript 引入了 Promise,這樣,不需要瀏覽器的安排,JavaScript 引擎本身也可以發(fā)起任務(wù)了

JS異步實現(xiàn)原理

js為單線程,js引擎中負(fù)責(zé)解析執(zhí)行js代碼的線程只有一個(主線程),即每次只能做一件事,其他IO操作放入任務(wù)隊列等待執(zhí)行,異步過程中,工作線程異步操作完成后需要通知主線程。那么這個通知機(jī)制是利用消息隊列事件循環(huán)(EventLoop)實際上,主線程只會做一件事情,就是從消息隊列里面取消息、執(zhí)行消息,再取消息、再執(zhí)行。當(dāng)消息隊列為空時,就會等待直到消息隊列變成非空。而且主線程只有在將當(dāng)前的消息執(zhí)行完成后,才會去取下一個消息
node:node.js單線程只是一個js主線程,本質(zhì)上的異步操作還是由線程池完成的,node將所有的阻塞操作都交給了內(nèi)部的線程池去實現(xiàn),本身只負(fù)責(zé)不斷的往返調(diào)度,并沒有進(jìn)行真正的I/O操作,從而實現(xiàn)異步非阻塞I/O,這便是node單線程的精髓之處了。

瀏覽器 概念

消息隊列:消息隊列是一個先進(jìn)先出的隊列,它里面存放著各種消息。

事件循環(huán):事件循環(huán)是指主線程重復(fù)從消息隊列中取消息、執(zhí)行的過程。(瀏覽器至少有一個事件循環(huán),一個事件循環(huán)至少有一個任務(wù)隊列(macrotask))

微任務(wù):

JavaScript 引擎發(fā)起的任務(wù) - JS 引擎級別

promise回調(diào),MutationObserver,process.nextTick,Object.observe

宏任務(wù)

宿主發(fā)起的任務(wù),每次的一段js代碼執(zhí)行過程,其實都是一個宏觀任務(wù) - 宿主級別

整體的js代碼,事件回調(diào),XHR回調(diào),定時器(setTimeout/setInterval/setImmediate),IO操作,UI render

宏任務(wù)和微任務(wù)關(guān)系:每個macro宏任務(wù)會維護(hù)一個micro微任務(wù)列表

事件循環(huán)過程

首先我們分析有多少個宏任務(wù);

在每個宏任務(wù)中,分析有多少個微任務(wù);

根據(jù)調(diào)用次序,確定宏任務(wù)中的微任務(wù)執(zhí)行次序;

根據(jù)宏任務(wù)的觸發(fā)規(guī)則和調(diào)用次序,確定宏任務(wù)的執(zhí)行次序;

確定整個順序

視圖渲染時機(jī):

本輪事件循環(huán)的microtask隊列被執(zhí)行完之后(不是每輪事件循環(huán)都會執(zhí)行視圖更新,瀏覽器有自己的優(yōu)化策略)

注意:執(zhí)行任務(wù)的耗時會影響視圖渲染的時機(jī)。通常瀏覽器以每秒60幀(60fps)的速率刷新頁面(16.7ms渲染一幀)所以如果要讓用戶覺得順暢,單個macrotask及它相關(guān)的所有microtask最好能在16.7ms內(nèi)完成。

Node 概念

非阻塞 I/O 操作:盡管 JavaScript 是單線程處理的——當(dāng)有可能的時候,它們會把操作轉(zhuǎn)移到系統(tǒng)內(nèi)核中去,當(dāng)其中的一個操作完成的時候,內(nèi)核通知 Node.js 將適合的回調(diào)函數(shù)添加到 輪詢 隊列中等待時機(jī)執(zhí)行

事件循環(huán)過程

過程

event loop 的每個階段都有一個任務(wù)隊列(一個 FIFO 隊列來執(zhí)行回調(diào))

當(dāng) event loop 到達(dá)某個階段時,將執(zhí)行該階段的任務(wù)隊列,直到隊列清空或執(zhí)行的回調(diào)達(dá)到系統(tǒng)上限后,才會轉(zhuǎn)入下一個階段

當(dāng)所有階段被順序執(zhí)行一次后,稱 event loop 完成了一個 tick

每次事件循環(huán)都包含了6個階段

timers 階段:這個階段執(zhí)行timer(setTimeout、setInterval)的回調(diào)

I/O callbacks 階段:執(zhí)行一些系統(tǒng)調(diào)用錯誤,比如網(wǎng)絡(luò)通信的錯誤回調(diào)

idle, prepare 階段:僅node內(nèi)部使用

poll 階段:獲取新的I/O事件, 適當(dāng)?shù)臈l件下node將阻塞在這里

check 階段:執(zhí)行 setImmediate() 的回調(diào)

close callbacks 階段:執(zhí)行 socketclose 事件回調(diào)

timers 階段

Node 會去檢查有無已過期的timer,如果有則把它的回調(diào)壓入timer的任務(wù)隊列中等待執(zhí)行

技術(shù)上來說,poll 階段控制 timers 什么時候執(zhí)行。

poll 階段

poll 階段主要有2個功能:

處理 poll 隊列的事件

當(dāng)有已超時的 timer,執(zhí)行它的回調(diào)函數(shù)

執(zhí)行過程:當(dāng)event loop進(jìn)入 poll 階段,并且 沒有設(shè)定的timers(there are no timers scheduled),會發(fā)生下面兩件事之一:

如果 poll 隊列不空,event loop會遍歷隊列并同步執(zhí)行回調(diào),直到隊列清空或執(zhí)行的回調(diào)數(shù)到達(dá)系統(tǒng)上限;

如果 poll 隊列為空,則發(fā)生以下兩件事之一:

如果代碼已經(jīng)被setImmediate()設(shè)定了回調(diào), event loop將結(jié)束 poll 階段進(jìn)入 check 階段來執(zhí)行 check 隊列(里的回調(diào))。

如果代碼沒有被setImmediate()設(shè)定回調(diào),event loop將阻塞在該階段等待回調(diào)被加入 poll 隊列,并立即執(zhí)行。

當(dāng)event loop進(jìn)入 poll 階段,并且 有設(shè)定的timers,一旦 poll 隊列為空(poll 階段空閑狀態(tài)): event loop將檢查timers,如果有1個或多個timers的下限時間已經(jīng)到達(dá),event loop將繞回 timers 階段,并執(zhí)行 timer隊列。

注意:沒有setImmediate()會導(dǎo)致event loop阻塞在poll階段,這樣之前設(shè)置的timer豈不是執(zhí)行不了了?所以咧,在poll階段event loop會有一個檢查機(jī)制,檢查timer隊列是否為空,如果timer隊列非空,event loop就開始下一輪事件循環(huán),即重新進(jìn)入到timer階段。

process.nextTick() VS setImmediate()

process.nextTick()

在各個事件階段之間執(zhí)行,一旦執(zhí)行,要直到nextTick隊列被清空,才會進(jìn)入到下一個事件階段

遞歸調(diào)用 process.nextTick(),會導(dǎo)致出現(xiàn)I/O starving(饑餓)

setImmediate

對比
setTimeout(()=>{
    console.log("timer1")

    Promise.resolve().then(function() {
        console.log("promise1")
    })
}, 0)

setTimeout(()=>{
    console.log("timer2")

    Promise.resolve().then(function() {
        console.log("promise2")
    })
}, 0)

//瀏覽器:
timer1
promise1
timer2
promise2

// node
timer1
timer2
promise1
promise2

http://lynnelv.github.io/img/...

http://lynnelv.github.io/img/...

補(bǔ)充閱讀

node單線程底層實現(xiàn)機(jī)制:

https://juejin.im/post/5b61d8...

https://yq.aliyun.com/article...

https://juejin.im/post/5b1e55...

node setTimeOut(), setInterval(), setImmediate() 以及 process.nextTick()區(qū)別

js 三種定時器的區(qū)別

https://www.cnblogs.com/onepi...

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/103765.html

相關(guān)文章

  • 淺談不同環(huán)境下的JavaScript執(zhí)行機(jī)制 + 示例詳解

    摘要:如果沒有其他異步任務(wù)要處理比如到期的定時器,會一直停留在這個階段,等待請求返回結(jié)果。執(zhí)行的執(zhí)行事件關(guān)閉請求的,例如事件循環(huán)的每一次循環(huán)都需要依次經(jīng)過上述的階段。因此,才會早于執(zhí)行。 showImg(https://segmentfault.com/img/bVbnY76); 概念 同步任務(wù)(Synchronous) 在主線程上排隊執(zhí)行的任務(wù),只有前一個任務(wù)執(zhí)行完畢,才能執(zhí)行后一個任務(wù) ...

    wanghui 評論0 收藏0
  • 總結(jié):JavaScript異步、事件循環(huán)消息隊列、任務(wù)任務(wù)

    摘要:單線程異步非阻塞然后,這又牽扯到了事件循環(huán)消息隊列,還有微任務(wù)宏任務(wù)這些。此步的位置不確定某個時刻后,定時器觸發(fā)線程通知事件觸發(fā)線程,事件觸發(fā)線程將回調(diào)函數(shù)加入消息隊列隊尾,等待引擎線程執(zhí)行。 前言 Philip Roberts 在演講 great talk at JSConf on the event loop 中說:要是用一句話來形容 JavaScript,我可能會這樣: Java...

    qianfeng 評論0 收藏0
  • Js事件循環(huán)(Event Loop)機(jī)制以及實例講解

    摘要:主線程要明確的一點是,主線程跟執(zhí)行棧是不同概念,主線程規(guī)定現(xiàn)在執(zhí)行執(zhí)行棧中的哪個事件。主線程循環(huán)即主線程會不停的從執(zhí)行棧中讀取事件,會執(zhí)行完所有棧中的同步代碼。以上參考資料詳解中的事件循環(huán)機(jī)制中的事件循環(huán)運行機(jī)制詳解再談 showImg(https://segmentfault.com/img/remote/1460000015317437?w=1920&h=1080); 前言 大家都...

    Anshiii 評論0 收藏0
  • JavaScript運行機(jī)制和事件循環(huán)

    摘要:主線程不斷重復(fù)上面的三步,此過程也就是常說的事件循環(huán)。所以主線程代碼執(zhí)行時間過長,會阻塞事件循環(huán)的執(zhí)行。參考資料這一次,徹底弄懂執(zhí)行機(jī)制任務(wù)隊列的順序機(jī)制事件循環(huán)搞懂異步事件輪詢與中的事件循環(huán) 1. 說明 讀過本文章后,您能知道: JavaScript代碼在瀏覽器中的執(zhí)行機(jī)制和事件循環(huán) 面試中經(jīng)常遇到的代碼輸出順序問題 首先通過一段代碼來驗證你是否了解代碼輸出順序,如果你不知道輸出...

    Ververica 評論0 收藏0
  • JavaScript 運行機(jī)制--Event Loop詳解

    摘要:上代碼代碼可以看出,不僅函數(shù)比指定的回調(diào)函數(shù)先執(zhí)行,而且函數(shù)也比先執(zhí)行。這是因為后一個事件進(jìn)入的時候,事件環(huán)可能處于不同的階段導(dǎo)致結(jié)果的不確定。這是因為因為執(zhí)行完后,程序設(shè)定了和,因此階段不會被阻塞進(jìn)而進(jìn)入階段先執(zhí)行,后進(jìn)入階段執(zhí)行。 JavaScript(簡稱JS)是前端的首要研究語言,要想真正理解JavaScript就繞不開他的運行機(jī)制--Event Loop(事件環(huán)) JS是一門...

    snifes 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<