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

資訊專欄INFORMATION COLUMN

Javascript 運(yùn)行機(jī)制詳解,Event Loop

Jingbin_ / 2477人閱讀

摘要:主線程在任務(wù)隊(duì)列中讀取事件,這個(gè)過(guò)程是循環(huán)不斷地,所以這種運(yùn)行機(jī)制叫做事件循環(huán)是在執(zhí)行棧同步代碼結(jié)束之后,下一次任務(wù)隊(duì)列執(zhí)行之前。

單線程

javascript為什么是單線程語(yǔ)言,原因在于如果是多線程,當(dāng)一個(gè)線程對(duì)DOM節(jié)點(diǎn)做添加內(nèi)容操作的時(shí)候,另一個(gè)線程要?jiǎng)h除這個(gè)DOM節(jié)點(diǎn),這個(gè)時(shí)候,瀏覽器應(yīng)該怎么選擇,這就造成了混亂,為了解決這類問(wèn)題,在一開(kāi)始的時(shí)候,javascript就采用單線程模式。

在后面H5出的web worker標(biāo)準(zhǔn)的時(shí)候,看似是多線程,其實(shí)是在一個(gè)主線程來(lái)控制其他線程,而且不能操作DOM,所以本質(zhì)還是單線程

任務(wù)隊(duì)列

任務(wù)可以分為兩種,一種為同步,另一種為異步(具有回調(diào)函數(shù))。如下圖:

所有的同步任務(wù)都在主線程上執(zhí)行,形成一個(gè)執(zhí)行棧 stack。當(dāng)所有同步任務(wù)執(zhí)行完畢后,它會(huì)去執(zhí)行microtask queue中的異步任務(wù)(nextTick,Promise),將他們?nèi)繄?zhí)行。主線程之外還有一個(gè)任務(wù)隊(duì)列task queue,當(dāng)有異步任務(wù)(DOM,AJAX,setTimeout,setImmediate)有結(jié)果的時(shí)候,就在任務(wù)隊(duì)列里放一個(gè)事件,一旦執(zhí)行棧和microtask queue任務(wù)執(zhí)行完畢,系統(tǒng)就會(huì)讀取任務(wù)隊(duì)列,將取出排在最前面的事件加入執(zhí)行棧執(zhí)行,這種機(jī)制就是任務(wù)隊(duì)列。

Event Loop

主線程在任務(wù)隊(duì)列中讀取事件,這個(gè)過(guò)程是循環(huán)不斷地,所以這種運(yùn)行機(jī)制叫做Event Loop(事件循環(huán))

nextTick、setImmediate、setTimeout

nextTick是在執(zhí)行棧同步代碼結(jié)束之后,下一次Event Loop(任務(wù)隊(duì)列)執(zhí)行之前。當(dāng)所有同步任務(wù)執(zhí)行完,會(huì)在queue中執(zhí)行nextTick,無(wú)論nextTick有多少層回調(diào),都會(huì)執(zhí)行完畢后再去任務(wù)隊(duì)列,所以會(huì)造成一直停留在當(dāng)前執(zhí)行棧,無(wú)法執(zhí)行任務(wù)隊(duì)列,請(qǐng)看下面代碼

process.nextTick(function () {
    console.log("nextTick1");
    process.nextTick(function (){console.log("nextTick2")});
});
  
setTimeout(function timeout() {
    console.log("setTimeout");
}, 0)

執(zhí)行完畢后輸出nextTick1、nextTick2、setTimeout,原因是nextTick是在當(dāng)前執(zhí)行棧末尾執(zhí)行,而setTimeout是在下次任務(wù)隊(duì)列在執(zhí)行

setImmediate方法是在Event Loop(任務(wù)隊(duì)列)末尾,也就是下一次Event Loop時(shí)執(zhí)行。
setTimeout方法是按照?qǐng)?zhí)行時(shí)間,放入任務(wù)隊(duì)列,有時(shí)快與setImmediate有時(shí)慢。請(qǐng)看以下代碼

setImmediate(function () {
    console.log("setImmediate1");
    setImmediate(function (){console.log("setImmediate2")});
});
  
setTimeout(function timeout() {
    console.log("setTimeout");
}, 0);

這段代碼執(zhí)行完可能是setImmediate1、setTimeout、setImmediate2,也可能是setTimeout、setImmediate1、setImmediate2,原因是setTimeout和setImmediate1都是在下次Event Loop中觸發(fā),所以先后不確定,但是setImmediate2肯定是最后,因?yàn)樗窃趕etImmediate1任務(wù)隊(duì)列之后,也就是下下次Event Loop執(zhí)行

Node.js的Event Loop

Node.js也是單線程的Event Loop但是和瀏覽器有些區(qū)別,如圖所示,

1.先通過(guò)Chrom V8引擎解析Javascript腳本

2.解析完畢后調(diào)用Node API

3.LIBUV庫(kù)負(fù)責(zé)Node API的執(zhí)行,將不同任務(wù)分配給不同的線程,形成一個(gè)Event Loop(任務(wù)隊(duì)列)

4.最后Chrom V8引擎將結(jié)果返回給用戶

Node.js Event Loop原理

node.js的特點(diǎn)是事件驅(qū)動(dòng),非阻塞單線程。當(dāng)應(yīng)用程序需要I/O操作的時(shí)候,線程并不會(huì)阻塞,而是把I/O操作交給底層庫(kù)(LIBUV)。此時(shí)node線程會(huì)去處理其他任務(wù),當(dāng)?shù)讓訋?kù)處理完I/O操作后,會(huì)將主動(dòng)權(quán)交還給Node線程,所以Event Loop的用處是調(diào)度線程,例如:當(dāng)?shù)讓訋?kù)處理I/O操作后調(diào)度Node線程處理后續(xù)工作,所以雖然node是單線程,但是底層庫(kù)處理操作依然是多線程

Node Event Loop的事件處理機(jī)制
   ┌───────────────────────┐

┌─>│        timers         │

│  └──────────┬────────────┘

│  ┌──────────┴────────────┐

│  │     I/O callbacks     │

│  └──────────┬────────────┘

│  ┌──────────┴────────────┐

│  │     idle, prepare     │

│  └──────────┬────────────┘      ┌───────────────┐

│  ┌──────────┴────────────┐      │   incoming:   │

│  │         poll          │<─────┤  connections, │

│  └──────────┬────────────┘      │   data, etc.  │

│  ┌──────────┴────────────┐      └───────────────┘

│  │        check          │

│  └──────────┬────────────┘

│  ┌──────────┴────────────┐

└──┤    close callbacks    │

   └───────────────────────┘

上面處理階段都是按照先進(jìn)先出的規(guī)則執(zhí)行回調(diào)函數(shù),按順序執(zhí)行,直到隊(duì)列為空或是該階段執(zhí)行的回調(diào)函數(shù)達(dá)到該階段所允許一次執(zhí)行回調(diào)函數(shù)的最大限制后,才會(huì)將操作權(quán)移交給下一階段。

timers: 用來(lái)檢查setTimeout()和setInterval()定時(shí)器是否到期,如果到期則執(zhí)行它,否則下一階段

I/O callbacks: 用來(lái)處理timers階段、setImmediate、和TCP他們的異常回調(diào)函數(shù)或者error

idle, prepare: nodejs內(nèi)部函數(shù)調(diào)用,在循環(huán)被I/O阻塞之前prepare回調(diào)就會(huì)立即調(diào)用

poll: 用來(lái)監(jiān)聽(tīng)fd的事件的,比如socket的可讀,可寫(xiě),文件的可讀可等等

check: setImmediate()函數(shù)只會(huì)在這個(gè)階段執(zhí)行

close callbacks: 執(zhí)行一些諸如關(guān)閉事件的回調(diào)函數(shù),如socket.on("close", ...)

具體分析,看下圖:

1.當(dāng)setTimeout時(shí)間最小,讀取文件不存在的時(shí)候

如圖所示,分別是nextTick、readFile、setTimeout、setImmediate,然而現(xiàn)在并沒(méi)有1.txt和2.txt文件,輸出結(jié)果是next Tick、setTimeout、readFile、setImmediate,在event loop中先判斷的是timeers,最先出書(shū)next Tick因?yàn)閜rocess.nextTick的實(shí)現(xiàn)是基于v8 MicroTask(是在當(dāng)前js call stack 中沒(méi)有可執(zhí)行代碼才會(huì)執(zhí)行的隊(duì)列,低于js call stack 代碼,但高于事件循環(huán),不屬于Event Loop,上面javascript的Event Loop介紹過(guò)了,所以最先輸出。然后開(kāi)始走Event Loop,第一階段是timers,判斷setTimeout到期,所以輸出setTimeout,進(jìn)入下一階段,poll將I/O操作權(quán)交出,新線程操作,但是并沒(méi)有相關(guān)讀取文件,所以直接返回回調(diào)函數(shù),所以處處readFile,最后到check階段,輸出setImmediate

2.當(dāng)setTimeout時(shí)間最小,讀取文件存在的時(shí)候

如圖所示,分別是nextTick、setTimeout、setImmediate、readFile,這次readFile在最后面,是因?yàn)槲募嬖?,?zhí)行到poll階段的時(shí)候,執(zhí)行I/O操作,node線程開(kāi)始執(zhí)行check階段,當(dāng)交出的I/O操作結(jié)束后,返回給Event Loop所以再執(zhí)行readFile的回調(diào)函數(shù),所以他在最后面

3.當(dāng)setTimeout時(shí)間為100毫秒,讀取文件不存在的時(shí)候
如圖所示,分別是nextTick、readFile、setImmediate、setTimeout,它和1不同的地方是setTimeout排在最后了,這是因?yàn)樵趫?zhí)行timers的時(shí)候,setTimeout沒(méi)有到期,所以直接執(zhí)行下一階段,當(dāng)執(zhí)行完poll的時(shí)候,會(huì)去執(zhí)行查看定時(shí)器有沒(méi)有到期,如果沒(méi)有下一次Event Loop再次查看,知道定時(shí)器到期,所以他在最后面

4.當(dāng)setTimeout時(shí)間為100毫秒,讀取文件存在的時(shí)候

如圖所示,分別是nextTick、setImmediate、readFile、setTimeout,它和2的區(qū)別是setTimeout在最后,原因和3一樣。

總結(jié)一下

1.javascript和node.js都是單線程,但是node底層是多線程操作

2.Event Loop —— 任務(wù)隊(duì)列

3.當(dāng)同時(shí)設(shè)置nextTick, setImmediate, setTimeout時(shí)一定是nextTick先執(zhí)行,nextTick不屬于Event LOop,它屬于v8的micro tasks,并且會(huì)阻塞Event Loop

4.setImmediate,setTimeout屬于Event Loop但是,直接階段不同

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

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

相關(guān)文章

  • JavaScript中線程運(yùn)行機(jī)制詳解

    摘要:中線程運(yùn)行機(jī)制詳解對(duì)于我們都知道,他是個(gè)單線程語(yǔ)言,但是準(zhǔn)確來(lái)說(shuō)它是擁有一個(gè)執(zhí)行程序主線程,和消息隊(duì)列輔線程,以及各個(gè)真正處理異步操作的工作線程。 JavaScript中線程運(yùn)行機(jī)制詳解 對(duì)于JavaScript我們都知道,他是個(gè)單線程語(yǔ)言,但是準(zhǔn)確來(lái)說(shuō)它是擁有一個(gè)執(zhí)行程序主線程,和消息隊(duì)列輔線程(Event Loop),以及各個(gè)真正處理異步操作的工作線程。當(dāng)主線程執(zhí)行JS程序的時(shí)候,...

    xiangchaobin 評(píng)論0 收藏0
  • JavaScript 運(yùn)行機(jī)制--Event Loop詳解

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

    snifes 評(píng)論0 收藏0
  • JavaScript Event Loop 機(jī)制詳解與 Vue.js 中實(shí)踐應(yīng)用

    摘要:機(jī)制詳解與中實(shí)踐應(yīng)用歸納于筆者的現(xiàn)代開(kāi)發(fā)語(yǔ)法基礎(chǔ)與實(shí)踐技巧系列文章。事件循環(huán)機(jī)制詳解與實(shí)踐應(yīng)用是典型的單線程單并發(fā)語(yǔ)言,即表示在同一時(shí)間片內(nèi)其只能執(zhí)行單個(gè)任務(wù)或者部分代碼片。 JavaScript Event Loop 機(jī)制詳解與 Vue.js 中實(shí)踐應(yīng)用歸納于筆者的現(xiàn)代 JavaScript 開(kāi)發(fā):語(yǔ)法基礎(chǔ)與實(shí)踐技巧系列文章。本文依次介紹了函數(shù)調(diào)用棧、MacroTask 與 Micr...

    livem 評(píng)論0 收藏0
  • JavaScript執(zhí)行機(jī)制、事件循環(huán)

    摘要:曾經(jīng)的理解首先,是單線程語(yǔ)言,也就意味著同一個(gè)時(shí)間只能做一件事,那么為什么不是多線程呢這樣還能提高效率啊假定同時(shí)有兩個(gè)線程,一個(gè)線程在某個(gè)節(jié)點(diǎn)上編輯了內(nèi)容,而另一個(gè)線程刪除了這個(gè)節(jié)點(diǎn),這時(shí)瀏覽器就很懵逼了,到底以執(zhí)行哪個(gè)操作呢所以,設(shè)計(jì)者把 Event Loop曾經(jīng)的理解 首先,JS是單線程語(yǔ)言,也就意味著同一個(gè)時(shí)間只能做一件事,那么 為什么JavaScript不是多線程呢?這樣還能提...

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

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

    Anshiii 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<