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

資訊專欄INFORMATION COLUMN

JavaScript運(yùn)行機(jī)制和事件循環(huán)

Ververica / 732人閱讀

摘要:主線程不斷重復(fù)上面的三步,此過(guò)程也就是常說(shuō)的事件循環(huán)。所以主線程代碼執(zhí)行時(shí)間過(guò)長(zhǎng),會(huì)阻塞事件循環(huán)的執(zhí)行。參考資料這一次,徹底弄懂執(zhí)行機(jī)制任務(wù)隊(duì)列的順序機(jī)制事件循環(huán)搞懂異步事件輪詢與中的事件循環(huán)

1. 說(shuō)明

讀過(guò)本文章后,您能知道:

JavaScript代碼在瀏覽器中的執(zhí)行機(jī)制和事件循環(huán)

面試中經(jīng)常遇到的代碼輸出順序問(wèn)題

首先通過(guò)一段代碼來(lái)驗(yàn)證你是否了解代碼輸出順序,如果你不知道輸出順序,那么本文可以幫助你了解:

console.log(1)
setTimeout(function () {
  new Promise(function (resolve) {
    console.log(2)
    resolve()
  })
  .then(() => { console.log(3) })
})
setTimeout(function () {
  console.log(4)
})
console.log(5)
2. JavaScript執(zhí)行機(jī)制

JavaScript語(yǔ)言的執(zhí)行是單線程(single thread)的。

所謂的單線程,就是指一次只執(zhí)行一個(gè)任務(wù),如果有多個(gè)任務(wù),就必須排隊(duì),前面一個(gè)任務(wù)完成,才能執(zhí)行后面任務(wù)。

這種模式的好處是實(shí)現(xiàn)起來(lái)比較簡(jiǎn)單,執(zhí)行環(huán)境相對(duì)單純;壞處是只要有一個(gè)任務(wù)耗時(shí)很長(zhǎng),后面的任務(wù)都必須排隊(duì)等待,會(huì)拖延整個(gè)程序的執(zhí)行。常見(jiàn)的瀏覽器無(wú)響應(yīng)(假死),往往就是因?yàn)槟骋欢蜫avaScript代碼長(zhǎng)時(shí)間運(yùn)行(比如死循環(huán)),導(dǎo)致整個(gè)頁(yè)面卡在這個(gè)地方,其他任務(wù)無(wú)法執(zhí)行。

為了解決這個(gè)問(wèn)題,JavaScript語(yǔ)言將任務(wù)的執(zhí)行模式分成兩種:同步(Synchronous)和異步(Asynchronous)。

同步任務(wù):在主線程上排隊(duì)執(zhí)行的任務(wù),只有前一個(gè)任務(wù)執(zhí)行完畢,才能執(zhí)行后一個(gè)任務(wù)。

異步任務(wù):不進(jìn)入主線程、而進(jìn)入"任務(wù)隊(duì)列"(task queue)的任務(wù),只有"任務(wù)隊(duì)列"通知主線程,某個(gè)異步任務(wù)可以執(zhí)行了,該任務(wù)才會(huì)進(jìn)入主線程執(zhí)行。

JavaScript執(zhí)行機(jī)制:

1、所有同步任務(wù)都在主線程上執(zhí)行,形成一個(gè)執(zhí)行棧(execution context stack)。
2、主線程之外,還存在一個(gè)"任務(wù)隊(duì)列"(task queue)。只要異步任務(wù)有了運(yùn)行結(jié)果,就在"任務(wù)隊(duì)列"之中放置一個(gè)事件。
3、一旦"執(zhí)行棧"中的所有同步任務(wù)執(zhí)行完畢,系統(tǒng)就會(huì)讀取"任務(wù)隊(duì)列",如果有有執(zhí)行任務(wù),則進(jìn)入執(zhí)行棧,開(kāi)始執(zhí)行。
4、主線程不斷重復(fù)上面的三步,此過(guò)程也就是常說(shuō)的Event Loop(事件循環(huán))。
3. JavaScript執(zhí)行機(jī)制中名詞介紹 3.1 執(zhí)行棧

當(dāng)我們調(diào)用一個(gè)方法的時(shí)候,js會(huì)生成一個(gè)與這個(gè)方法相對(duì)應(yīng)的執(zhí)行環(huán)境,也叫執(zhí)行上下文,這個(gè)執(zhí)行環(huán)境存在著這個(gè)方法的私有作用域、參數(shù)、this對(duì)象等等。因?yàn)閖s是單線程的,同一時(shí)間只能執(zhí)行一個(gè)方法,所以當(dāng)一系列的方法被依次調(diào)用的時(shí)候,js會(huì)先解析這些方法,把其中的同步任務(wù)按照?qǐng)?zhí)行順序排隊(duì)到一個(gè)地方,這個(gè)地方叫做執(zhí)行棧。

3.2 主線程

JavaScript是單線程的,那么這個(gè)單線程就成為主線程。而事件循環(huán)在主線程執(zhí)行完執(zhí)行棧代碼后,才執(zhí)行的。所以主線程代碼執(zhí)行時(shí)間過(guò)長(zhǎng),會(huì)阻塞事件循環(huán)的執(zhí)行。只有當(dāng)執(zhí)行棧為空的時(shí)候(同步代碼執(zhí)行完畢),才會(huì)執(zhí)行事件循環(huán)來(lái)觀察有哪些事件回調(diào)需要執(zhí)行,當(dāng)事件循環(huán)檢測(cè)到任務(wù)隊(duì)列有事件就讀取出回調(diào)放到執(zhí)行棧由主線程執(zhí)行。

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

任務(wù)隊(duì)列也有時(shí)稱叫消息隊(duì)列、回調(diào)隊(duì)列。

異步操作會(huì)將相關(guān)回調(diào)添加到任務(wù)隊(duì)列中。而不同的異步操作添加到任務(wù)隊(duì)列的時(shí)機(jī)也不同,如onclick, setTimeout,ajax處理的方式都不同,這些異步操作是由瀏覽器內(nèi)核的webcore來(lái)執(zhí)行的,webcore包含下圖中的3種 webAPI,分別是DOM Binding、network、timer模塊。

DOM Binding 模塊處理一些DOM綁定事件,如onclick事件觸發(fā)時(shí),回調(diào)函數(shù)會(huì)立即被webcore添加到任務(wù)隊(duì)列中。

network 模塊處理Ajax請(qǐng)求,在網(wǎng)絡(luò)請(qǐng)求返回時(shí),才會(huì)將對(duì)應(yīng)的回調(diào)函數(shù)添加到任務(wù)隊(duì)列中。

timer 模塊會(huì)對(duì)setTimeout等計(jì)時(shí)器進(jìn)行延時(shí)處理,當(dāng)時(shí)間到達(dá)的時(shí)候,才會(huì)將回調(diào)函數(shù)添加到任務(wù)隊(duì)列中。

3.4 事件循環(huán)

如上圖所示,JavaScript整體執(zhí)行過(guò)程:

主線程運(yùn)行的時(shí)候會(huì)生成堆(heap)和棧(stack);

js從上到下解析方法,將其中的同步任務(wù)按照?qǐng)?zhí)行順序排列到執(zhí)行棧中;

當(dāng)程序調(diào)用外部的API時(shí),比如ajax、setTimeout等,會(huì)將此類異步任務(wù)掛起,繼續(xù)執(zhí)行執(zhí)行棧中的任務(wù),等異步任務(wù)返回結(jié)果后,再按照?qǐng)?zhí)行順序排列到任務(wù)隊(duì)列中;

主線程先將執(zhí)行棧中的同步任務(wù)清空,然后檢查任務(wù)隊(duì)列中是否有任務(wù),如果有,就將第一個(gè)事件對(duì)應(yīng)的回調(diào)推到執(zhí)行棧中執(zhí)行,若在執(zhí)行過(guò)程中遇到異步任務(wù),則繼續(xù)將這個(gè)異步任務(wù)排列到任務(wù)隊(duì)列中。

主線程每次將執(zhí)行棧清空后,就去任務(wù)隊(duì)列中檢查是否有任務(wù),如果有,就每次取出一個(gè)推到執(zhí)行棧中執(zhí)行,這個(gè)過(guò)程是循環(huán)往復(fù)的... ...,這個(gè)過(guò)程被稱為“Event Loop 事件循環(huán)”。

也可以參考如下鏈接:https://html.spec.whatwg.org/...

4. 宏任務(wù)和微任務(wù)

出現(xiàn)Promise后,JavaScript對(duì)于任務(wù)的定義除了廣義的同步任務(wù)和異步任務(wù),又對(duì)任務(wù)做了更精細(xì)的定義,macrotask(宏任務(wù))和 microtask(微任務(wù)):

macrotask(按優(yōu)先級(jí)順序排列): script(你的全部JS代碼,“同步代碼”), setTimeout, setInterval, setImmediate(node的), I/O,UI rendering

microtask(按優(yōu)先級(jí)順序排列):process.nextTick(node的),Promise(這里指瀏覽器原生實(shí)現(xiàn)的 Promise), Object.observe, MutationObserver

注意:宏任務(wù)、微任務(wù)中出現(xiàn)的nodejs中的方法是nodejs專有的,瀏覽器的JavaScript環(huán)境暫時(shí)沒(méi)有支持。

4.1 事件循環(huán)對(duì)宏任務(wù)和微任務(wù)的處理

有了宏任務(wù)和微任務(wù)后,JavaScript事件循環(huán)對(duì)此處理方法如下形式:

js引擎首先從macrotask queue中取出第一個(gè)任務(wù),執(zhí)行完畢后,將microtask queue中的所有任務(wù)取出,按順序全部執(zhí)行;

然后再?gòu)膍acrotask queue(宏任務(wù)隊(duì)列)中取下一個(gè),執(zhí)行完畢后,再次將microtask queue(微任務(wù)隊(duì)列)中的全部取出;

循環(huán)往復(fù),直到兩個(gè)queue中的任務(wù)都取完。

注意::此處把執(zhí)行同步代碼算成第一個(gè)宏任務(wù)了。

5. 一個(gè)實(shí)際例子講解JavaScript執(zhí)行流程

如下代碼:

console.log("1");
setTimeout(function() {
  console.log("2");
  new Promise(function(resolve) {
      console.log("3");
      resolve();
  }).then(function() {
      console.log("4")
  })
})
console.log("5");
setTimeout(function() {
  console.log("6");
  new Promise(function(resolve) {
      console.log("7");
      resolve();
  }).then(function() {
      console.log("8")
  })
})
console.log("9");

上面代碼執(zhí)行過(guò)程:

第一輪事件循環(huán)

整體script代碼(同步代碼)作為第一個(gè)宏任務(wù)進(jìn)入主線程,遇到console.log,輸出1

遇到setTimeout,其回調(diào)函數(shù)被放到宏任務(wù)隊(duì)列中,暫記為setTmineout1

遇到console.log,輸出5

遇到setTimeout,其回調(diào)函數(shù)被放到宏任務(wù)隊(duì)列中,暫記為setTmineout2

遇到console.log,輸出9

一個(gè)宏任務(wù)執(zhí)行結(jié)束,去微任務(wù)隊(duì)列查找是否有待執(zhí)行的任務(wù),沒(méi)有,結(jié)束

第一輪循環(huán)結(jié)束,輸出:1 5 9

第二輪事件循環(huán)

從宏任務(wù)隊(duì)列中取出一個(gè)任務(wù),即setTmineout1,開(kāi)始執(zhí)行

遇到console.log,輸出2

遇到Promise,創(chuàng)建Promise,輸出了3,同時(shí)把Promise.then回調(diào)函數(shù)放到微任務(wù)隊(duì)列

一個(gè)宏任務(wù)執(zhí)行結(jié)束,去微任務(wù)隊(duì)列查找是否有待執(zhí)行的任務(wù), 發(fā)現(xiàn)有微任務(wù),全部取出放到執(zhí)行棧執(zhí)行

執(zhí)行微任務(wù),此時(shí)就一個(gè)微任務(wù),console.log,輸出4

微任務(wù)執(zhí)行結(jié)束

第二輪循環(huán)結(jié)束,輸出:2 4

第三輪事件循環(huán)與第二輪一樣,輸出:6 7 8

事件循環(huán)發(fā)現(xiàn)所有任務(wù)都已經(jīng)處理完畢,此時(shí)程序執(zhí)行結(jié)束

全部的輸出:1 5 9 2 3 4 6 7 8,可復(fù)制代碼到chrome瀏覽器控制臺(tái)中運(yùn)行校驗(yàn)結(jié)果

注意:瀏覽器環(huán)境JavaScript的執(zhí)行機(jī)制和node中JavaScript的執(zhí)行機(jī)制是不同的。

參考資料

這一次,徹底弄懂 JavaScript 執(zhí)行機(jī)制

JavaScript任務(wù)隊(duì)列的順序機(jī)制(事件循環(huán))

搞懂 JavsScript 異步 —? 事件輪詢

JS與Node.js中的事件循環(huán)

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

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

相關(guān)文章

  • JavaScript 運(yùn)行機(jī)制詳解(理解同步、異步事件循環(huán))

    摘要:從異步過(guò)程的角度看,函數(shù)就是異步過(guò)程的發(fā)起函數(shù),事件監(jiān)聽(tīng)函數(shù)就是異步過(guò)程的回調(diào)函數(shù)。事件觸發(fā)時(shí),表示異步任務(wù)完成,會(huì)將事件監(jiān)聽(tīng)器函數(shù)封裝成一條消息放到消息隊(duì)列中,等待主線程執(zhí)行。 1.為什么JavaScript是單線程? JavaScript語(yǔ)言的一大特點(diǎn)就是單線程,也就是說(shuō),同一個(gè)時(shí)間只能做一件事。那么,為什么JavaScript不能有多個(gè)線程呢?這樣能提高效率啊。JavaScrip...

    loonggg 評(píng)論0 收藏0
  • JS與Node.js中的事件循環(huán)

    摘要:的單線程,與它的用途有關(guān)。特點(diǎn)的顯著特點(diǎn)異步機(jī)制事件驅(qū)動(dòng)。隊(duì)列的讀取輪詢線程,事件的消費(fèi)者,的主角。它將不同的任務(wù)分配給不同的線程,形成一個(gè)事件循環(huán),以異步的方式將任務(wù)的執(zhí)行結(jié)果返回給引擎。 這兩天跟同事同事討論遇到的一個(gè)問(wèn)題,js中的event loop,引出了chrome與node中運(yùn)行具有setTimeout和Promise的程序時(shí)候執(zhí)行結(jié)果不一樣的問(wèn)題,從而引出了Nodejs的...

    abson 評(píng)論0 收藏0
  • JS是單線程,你了解其運(yùn)行機(jī)制嗎?

    摘要:的單線程,與它的用途有關(guān)。事件循環(huán)事件循環(huán)是指主線程重復(fù)從消息隊(duì)列中取消息執(zhí)行的過(guò)程。到此為止,就完成了工作線程對(duì)主線程的通知,回調(diào)函數(shù)也就得到了執(zhí)行。 一. 區(qū)分進(jìn)程和線程 很多新手是區(qū)分不清線程和進(jìn)程的,沒(méi)有關(guān)系。這很正常。先看看下面這個(gè)形象的比喻: 進(jìn)程是一個(gè)工廠,工廠有它的獨(dú)立資源-工廠之間相互獨(dú)立-線程是工廠中的工人,多個(gè)工人協(xié)作完成任務(wù)-工廠內(nèi)有一個(gè)或多個(gè)工人-工人之間共享...

    AlphaGooo 評(píng)論0 收藏0
  • Javascript系列之javascript機(jī)制

    摘要:異步任務(wù)必須指定回調(diào)函數(shù),當(dāng)異步任務(wù)從任務(wù)隊(duì)列回到執(zhí)行棧,回調(diào)函數(shù)就會(huì)執(zhí)行。事件循環(huán)主線程從任務(wù)隊(duì)列中讀取事件,這個(gè)過(guò)程是循環(huán)不斷的,所以整個(gè)的這種運(yùn)行機(jī)制又稱為。事件循環(huán)事件循環(huán)是指主線程重復(fù)從消息隊(duì)列中取消息執(zhí)行的過(guò)程。 參考鏈接:這一次,徹底弄懂 JavaScript 執(zhí)行機(jī)制https://zhuanlan.zhihu.com/p/...從瀏覽器多進(jìn)程到JS單線程,JS運(yùn)行機(jī)制...

    13651657101 評(píng)論0 收藏0
  • JavaScript執(zhí)行機(jī)制

    摘要:事件循環(huán)事件循環(huán)是實(shí)現(xiàn)異步的一種方法,也是的執(zhí)行機(jī)制。最后的最后是一門單線程語(yǔ)言是的執(zhí)行機(jī)制部分內(nèi)容轉(zhuǎn)自 1.單線程 javascript是一門單線程語(yǔ)言 2.javascript事件循環(huán) 同步任務(wù) 異步任務(wù) showImg(https://segmentfault.com/img/bVbufUd?w=1268&h=1062);除了廣義的同步任務(wù)和異步任務(wù),我們對(duì)任務(wù)有更精細(xì)的定義...

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

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

0條評(píng)論

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