<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          JS時(shí)間循環(huán)-宏任務(wù)與微任務(wù)

          共 3234字,需瀏覽 7分鐘

           ·

          2021-01-05 23:02

          1、關(guān)于JavaScript

          JavaScript是一門單線程語(yǔ)言,在最新的html5中提出了Web-Worker,但javascript是單線程這一核心仍未改變。所以一切javascript版的"多線程"都是用單線程模擬出來(lái)的,一切javascript多線程都是紙老虎!

          2、javascript事件循環(huán)

          既然js是單線程,那就像只有一個(gè)窗口的銀行,客戶需要排隊(duì)一個(gè)一個(gè)辦理業(yè)務(wù),同理js任務(wù)也要一個(gè)一個(gè)順序執(zhí)行。如果一個(gè)任務(wù)耗時(shí)過(guò)長(zhǎng),那么后一個(gè)任務(wù)也必須等著。
          那么問(wèn)題來(lái)了,假如我們想瀏覽新聞,但是新聞包含的超清圖片加載很慢,難道我們的網(wǎng)頁(yè)要一直卡著直到圖片完全顯示出來(lái)?因此聰明的程序員將任務(wù)分為兩類:
          • 同步任務(wù)
          • 異步任務(wù)
          當(dāng)我們打開(kāi)網(wǎng)站時(shí),網(wǎng)頁(yè)的渲染過(guò)程就是一大堆同步任務(wù),比如頁(yè)面骨架和頁(yè)面元素的渲染。而像加載圖片音樂(lè)之類占用資源大耗時(shí)久的任務(wù),就是異步任務(wù)。
          關(guān)于這部分有嚴(yán)格的文字定義,但本文的目的是用最小的學(xué)習(xí)成本徹底弄懂執(zhí)行機(jī)制,所以我們用導(dǎo)圖來(lái)說(shuō)明:


          導(dǎo)圖要表達(dá)的內(nèi)容用文字來(lái)表述的話:

          • 同步和異步任務(wù)分別進(jìn)入不同的執(zhí)行"場(chǎng)所",同步的進(jìn)入主線程,異步的進(jìn)入Event Table并注冊(cè)函數(shù)。

          • 當(dāng)指定的事情完成時(shí),Event Table會(huì)將這個(gè)函數(shù)移入Event Queue。

          • 主線程內(nèi)的任務(wù)執(zhí)行完畢為空,會(huì)去Event Queue讀取對(duì)應(yīng)的函數(shù),進(jìn)入主線程執(zhí)行。

          • 上述過(guò)程會(huì)不斷重復(fù),也就是常說(shuō)的Event Loop(事件循環(huán))。

          我們不禁要問(wèn)了,那怎么知道主線程執(zhí)行棧為空啊?js引擎存在monitoring process進(jìn)程,會(huì)持續(xù)不斷的檢查主線程執(zhí)行棧是否為空,一旦為空,就會(huì)去Event Queue那里檢查是否有等待被調(diào)用的函數(shù)。

          3、Promise與process.nextTick(callback)

          Promise的定義和功能本文不再贅述,不了解的讀者可以學(xué)習(xí)一下阮一峰老師的Promise。而process.nextTick(callback)類似node.js版的"setTimeout",在事件循環(huán)的下一次循環(huán)中調(diào)用 callback 回調(diào)函數(shù)。

          我們進(jìn)入正題,除了廣義的同步任務(wù)和異步任務(wù),我們對(duì)任務(wù)有更精細(xì)的定義:

          • macro-task(宏任務(wù)):包括整體代碼script,setTimeout,setInterval

          • micro-task(微任務(wù)):Promise,process.nextTick

          不同類型的任務(wù)會(huì)進(jìn)入對(duì)應(yīng)的Event Queue,比如setTimeout和setInterval會(huì)進(jìn)入相同的Event Queue。

          事件循環(huán)的順序,決定js代碼的執(zhí)行順序。進(jìn)入整體代碼(宏任務(wù))后,開(kāi)始第一次循環(huán)。接著執(zhí)行所有的微任務(wù)。然后再次從宏任務(wù)開(kāi)始,找到其中一個(gè)任務(wù)隊(duì)列執(zhí)行完畢,再執(zhí)行所有的微任務(wù)。



          事件循環(huán)的進(jìn)程模型

          • 選擇當(dāng)前要執(zhí)行的任務(wù)隊(duì)列,選擇任務(wù)隊(duì)列中最先進(jìn)入的任務(wù),如果任務(wù)隊(duì)列為空即null,則執(zhí)行跳轉(zhuǎn)到微任務(wù)(MicroTask)的執(zhí)行步驟。

          • 將事件循環(huán)中的任務(wù)設(shè)置為已選擇任務(wù)。

          • 執(zhí)行任務(wù)。

          • 將事件循環(huán)中當(dāng)前運(yùn)行任務(wù)設(shè)置為null。

          • 將已經(jīng)運(yùn)行完成的任務(wù)從任務(wù)隊(duì)列中刪除。

          • microtasks步驟:進(jìn)入microtask檢查點(diǎn)。

          • 更新界面渲染。

          • 返回第一步。


          執(zhí)行棧在執(zhí)行完同步任務(wù)后,查看執(zhí)行棧是否為空,如果執(zhí)行棧為空,就會(huì)去檢查微任務(wù)(microTask)隊(duì)列是否為空,如果為空的話,就執(zhí)行Task(宏任務(wù)),否則就一次性執(zhí)行完所有微任務(wù)。

          每次單個(gè)宏任務(wù)執(zhí)行完畢后,檢查微任務(wù)(microTask)隊(duì)列是否為空,如果不為空的話,會(huì)按照先入先出的規(guī)則全部執(zhí)行完微任務(wù)(microTask)后,設(shè)置微任務(wù)(microTask)隊(duì)列為null,然后再執(zhí)行宏任務(wù),如此循環(huán)。

          例子:


          ?輸出結(jié)果:

          1 7 6 8 2 4 3 5 9 11 10 12

          4.process.nextTick和Promise都是Microtasks(微任務(wù)),為什么process.nextTick會(huì)先執(zhí)行?


          rocess.nextTick 永遠(yuǎn)大于 promise.then,原因其實(shí)很簡(jiǎn)單。。。在Node中,_tickCallback在每一次執(zhí)行完TaskQueue中的一個(gè)任務(wù)后被調(diào)用,而這個(gè)_tickCallback中實(shí)質(zhì)上干了兩件事:

          1、nextTickQueue中所有任務(wù)執(zhí)行掉(長(zhǎng)度最大1e4,Node版本v6.9.1)

          2、第一步執(zhí)行完后執(zhí)行_runMicrotasks函數(shù),執(zhí)行microtask(微任務(wù))中的部分(promise.then注冊(cè)的回調(diào))

          所以很明顯 process.nextTick > promise.then

          5、總結(jié)

          (1)js的異步

          我們從最開(kāi)頭就說(shuō)javascript是一門單線程語(yǔ)言,不管是什么新框架新語(yǔ)法糖實(shí)現(xiàn)的所謂異步,其實(shí)都是用同步的方法去模擬的,牢牢把握住單線程這點(diǎn)非常重要。

          (2)事件循環(huán)Event Loop

          事件循環(huán)是js實(shí)現(xiàn)異步的一種方法,也是js的執(zhí)行機(jī)制。

          (3)javascript的執(zhí)行和運(yùn)行

          執(zhí)行和運(yùn)行有很大的區(qū)別,javascript在不同的環(huán)境下,比如node,瀏覽器,Ringo等等,執(zhí)行方式是不同的。而運(yùn)行大多指javascript解析引擎,是統(tǒng)一的。

          (4)setImmediate

          微任務(wù)和宏任務(wù)還有很多種類,比如setImmediate等等,執(zhí)行都是有共同點(diǎn)的,有興趣的同學(xué)可以自行了解。

          (5)最后的最后

          • javascript是一門單線程語(yǔ)言

          • Event Loop是javascript的執(zhí)行機(jī)制

          6、深入淺出分析process.nextTick()?

          process.nextTick() 是 Node 的一個(gè)定時(shí)器,讓任務(wù)可以在指定的時(shí)間運(yùn)行。其中 Node 一共提供了 4 個(gè)定時(shí)器,它們分別是 setTimeout()、setInterval()、setImmediate()、process.nextTick()。

          process.nextTick()?這個(gè)名字有點(diǎn)誤導(dǎo),它是在本輪循環(huán)執(zhí)行的,而且是所有異步任務(wù)里面最快執(zhí)行的。

          Node 執(zhí)行完所有同步任務(wù),接下來(lái)就會(huì)執(zhí)行process.nextTick的任務(wù)隊(duì)列。所以,下面這行代碼是第二個(gè)輸出結(jié)果。

          process.nextTick(() => console.log(3));

          基本上,如果你希望異步任務(wù)盡可能快地執(zhí)行,那就使用 process.nextTick。

          根據(jù)語(yǔ)言規(guī)格,Promise 對(duì)象的回調(diào)函數(shù),會(huì)進(jìn)入異步任務(wù)里面的”微任務(wù)”(microtask)隊(duì)列。
          微任務(wù)隊(duì)列追加在 process.nextTick 隊(duì)列的后面,也屬于本輪循環(huán)。所以,下面的代碼總是先輸出 3,再輸出 4。

          process.nextTick(() => console.log(3));Promise.resolve().then(() => console.log(4)); // 3 // 4

          注意,只有前一個(gè)隊(duì)列全部清空以后,才會(huì)執(zhí)行下一個(gè)隊(duì)列。

          process.nextTick(() => console.log(1));Promise.resolve().then(() => console.log(2));process.nextTick(() => console.log(3));Promise.resolve().then(() => console.log(4)); // 1 // 3 // 2 // 4

          上面代碼中,全部 process.nextTick 的回調(diào)函數(shù),執(zhí)行都會(huì)早于 Promise 的。


          本文完?


          瀏覽 74
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  亚洲日韩中文字幕 | 日逼视频| 日韩动态视频 | 日韩无在线 | 黑丝空姐在线观看视频 |