国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

瀏覽器環(huán)境下的microtaks和macrotasks

econi / 2426人閱讀

摘要:的回調(diào)函數(shù)正是處于隊(duì)列之中。將看做會導(dǎo)致性能問題,回調(diào)函數(shù)可能會因?yàn)殇秩镜认嚓P(guān)產(chǎn)生不必要的延后。瀏覽器是怎么出錯(cuò)的和在兩次點(diǎn)擊操作之間運(yùn)行完成了所有的,就比如的回調(diào)函數(shù)所展示的,但是似乎有不同的排序算法。

帶有可視代碼執(zhí)行順序的原文鏈接https://jakearchibald.com/201...,
此篇文字并非其完整翻譯,加入了一部分自己的理解,比如將其中的task替換為macrotask或是刪除了可視代碼執(zhí)行順序的逐步解釋。
運(yùn)行順序

參考以下JavaScript代碼:

    console.log("script start");

    setTimeout(function() {
    console.log("setTimeout");
    }, 0);

    Promise.resolve().then(function() {
    console.log("promise1");
    }).then(function() {
    console.log("promise2");
    });

    console.log("script end");
    /*
     * script start
     * script end
     * promise1
     * promise2
     * setTimeout
     */

但是,在 Microsoft Edge, Firefox 40, iOS Safari 和 桌面版 Safari 8.0.8 中,setTimeout會優(yōu)先于promise1promise2。而令人奇怪的是,在 Firefox 39 和 Safari 8.0.7 中又是一致的。

為什么會這樣

Macrotask

想要理解這部分內(nèi)容,你需要知道事件循環(huán)和microtasks。如果你是第一次接觸相關(guān)內(nèi)容,可能會需要一些精力,別緊張,大家都會這樣,深呼吸…

在瀏覽器中,每一個(gè)thread(可以理解為每一個(gè)頁簽)都有自己的事件循環(huán),因此,它們可以相互獨(dú)立執(zhí)行自身的Macrotask,然而,同源的窗口會分享同一個(gè)事件循環(huán)來保證相互可以進(jìn)行同步通訊行為。事件循環(huán)會持續(xù)運(yùn)行下去,用于執(zhí)行當(dāng)前存在的所有任務(wù)列表。每一個(gè)事件循環(huán)存在多個(gè)不同的任務(wù)隊(duì)列用以保證執(zhí)行順序,而瀏覽器會依照任務(wù)類別來從任務(wù)序列中選取一個(gè)任務(wù)來進(jìn)行執(zhí)行。這使得瀏覽器可以優(yōu)先選擇執(zhí)行更為重要的任務(wù),比如用戶輸入操作。

Macrotask是已經(jīng)被排序完成的,因此瀏覽器可以通過內(nèi)部的機(jī)制來直接將其放置于javascript/DOM程序域中并確保每一個(gè)程序步驟的順序執(zhí)行。而在兩個(gè)任務(wù)執(zhí)行間隔之中,瀏覽器 可能 會執(zhí)行更新操作。比如處理獲取用戶點(diǎn)擊的回調(diào)函數(shù),分析HTML,又或者是setTimeout

setTimeout等待一個(gè)指定的時(shí)間延遲然后加入一個(gè)新的任務(wù)來執(zhí)行對應(yīng)的回調(diào)函數(shù)。這就是為什么setTimeout會延遲于script end,因?yàn)?em>script end是第一個(gè)任務(wù)的程序內(nèi)容,而setTimeout是來之后續(xù)的另一個(gè)任務(wù)。

Microtasks

Microtasks通常用于排列那些應(yīng)當(dāng)在當(dāng)前任務(wù)執(zhí)行完畢后立即執(zhí)行的任務(wù),比如對某些事件作出反應(yīng),或是一些不會影響新任務(wù)的異步操作。這個(gè)Microtasks序列是在沒有其他JavaScript任務(wù)正在執(zhí)行,同時(shí)在其他Macrotask執(zhí)行完畢之后。任何新添加的Microtasks會被排列到Microtasks的隊(duì)尾并進(jìn)行處理。promise的回調(diào)函數(shù)正是處于Microtasks隊(duì)列之中。

當(dāng)一個(gè)promise結(jié)束掉以后,或者它在之前已經(jīng)處理完畢,那么會添加一個(gè)回饋結(jié)果的回調(diào)函數(shù)至Microtasks的隊(duì)尾。這確保了promise的回調(diào)函數(shù)永遠(yuǎn)是異步執(zhí)行的,即使promise已經(jīng)在當(dāng)前的時(shí)間片執(zhí)行完畢。因此在調(diào)用.then(yey,nay)時(shí)并不會直接將一個(gè)Macrotask添加至隊(duì)尾。這就是為什么promise1promise2會晚于script end,當(dāng)前運(yùn)行的Macrotask一定會在Macrotask處理前執(zhí)行完畢。promise1promise2早于setTimeout輸出,則是因?yàn)閙icrotasks永遠(yuǎn)在下一個(gè)Macrotask啟動前結(jié)束。

為什么有些瀏覽器表現(xiàn)不一致

有些瀏覽器的輸出順序?yàn)椋?em>script start, script end, setTimeout, promise1, promise2。它們在執(zhí)行setTimeout后才運(yùn)行primise的回調(diào)函數(shù)。這就好像是它們更傾向于將promise的回調(diào)函數(shù)看做Macrotask的一類。

這其實(shí)是可以理解的,promise是來自于ECMAScript而非HTML。ECMAScript擁有一個(gè)類似于Macrotask的"jobs"的概念,但這種關(guān)系并不能很清晰的區(qū)分開vague mailing list discussions。無論如何,更為普遍的觀點(diǎn)是,promise是屬于microtask,并且有一些很好的理由。

將promise看做Macrotask會導(dǎo)致性能問題,回調(diào)函數(shù)可能會因?yàn)殇秩镜认嚓P(guān)Macrotask產(chǎn)生不必要的延后。同時(shí)也會導(dǎo)致影響其他的Macrotask,并且可能打斷和其他api的交互,并導(dǎo)致其延后。

這里有個(gè)將promise當(dāng)做microtasks處理的類似說明,an Edge ticket。WebKit內(nèi)核的做法顯然是正確的,因此我推斷Safari最終也會選擇修復(fù)這個(gè)問題,同時(shí)Firefox43似乎也已經(jīng)修復(fù)了這個(gè)問題。

如何判斷是Macrotask還是Microtask

直接進(jìn)行測試是一種辦法。在瀏覽器中直接查看關(guān)于promisesetTimeout的輸出,盡管你依賴的實(shí)現(xiàn)是正確的。

就像之前所提到的,在ECMAScript中,它們稱microtasks為“jobs”。在step 8.a of PerformPromiseThen中,EnqueueJob被稱為添加一個(gè)microtask。

現(xiàn)在,讓我們看一個(gè)更復(fù)雜的例子。

加入MutationObserver

首先讓我們寫一段html代碼:

接下來是一段JS:

// Let"s get hold of those elements
var outer = document.querySelector(".outer");
var inner = document.querySelector(".inner");

// Let"s listen for attribute changes on the
// outer element
new MutationObserver(function() {
  console.log("mutate");
}).observe(outer, {
  attributes: true
});

// Here"s a click listener…
function onClick() {
  console.log("click");

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

  Promise.resolve().then(function() {
    console.log("promise");
  });

  outer.setAttribute("data-random", Math.random());
}

// …which we"ll attach to both elements
inner.addEventListener("click", onClick);
outer.addEventListener("click", onClick);

    /*
     *click
     *promise
     *mutate
     *click
     *promise
     *mutate
     *timeout
     *timeout
     */

在不同瀏覽器中的表現(xiàn):
Chrome:
click
promise
mutate
click
promise
mutate
timeout
timeout

FireFox:
click
mutate
click
mutate
timeout
promise
promise
timeout

Safari:
click
mutate
click
mutate
promise
promise
timeout
timeout

Edge:
click
click
mutate
timeout
promise
timeout
promise

哪個(gè)是正確的

拋出‘click’事件的是一個(gè)macrotask,Mutation observer 和 promise 的回調(diào)函數(shù)被當(dāng)做microtask進(jìn)行排列。setTimeout的回調(diào)會被當(dāng)做一個(gè) macrotask。

因此Chrome的運(yùn)行結(jié)果才是正確的。這里有點(diǎn)奇特的地方反而是microtask在回調(diào)函數(shù)之后執(zhí)行(直到?jīng)]有其他的代碼在執(zhí)行),我認(rèn)為這里是限制了marcotask的完成。這條用于限制回調(diào)函數(shù)的規(guī)則來源自HTML:

If the stack of script settings objects is now empty, perform a microtask checkpoint
— HTML: Cleaning up after a callback step 3

同時(shí)一個(gè)microtask checkpoint遍歷了整個(gè)microtask隊(duì)列,除非我們已經(jīng)在執(zhí)行microtask隊(duì)列。類似的,ECMAScript 描述了jobs:

Execution of a Job can be initiated only when there is no running execution context and the execution context stack is empty…(Job可以在沒有可執(zhí)行環(huán)境和可執(zhí)行環(huán)境的堆為空的情況下被初始化)
— ECMAScript: Jobs and Job Queues

盡管這里的“can be”在HTML環(huán)境中變成了“must be”。

瀏覽器是怎么出錯(cuò)的?

FirefoxSafari在兩次點(diǎn)擊操作之間運(yùn)行完成了所有的microtasks,就比如mutation的回調(diào)函數(shù)所展示的,但是promise似乎有不同的排序算法。這是可以理解的,因?yàn)閖obs和microtasks之間的聯(lián)系是相對模糊的,但我依然可以確定他們會在兩次點(diǎn)擊回調(diào)操作之間運(yùn)行完成。Firefox ticket.Safari ticket.

對于Edge我們已經(jīng)可以確定它對于promise的隊(duì)列類別是不正確的,但它依然在兩次點(diǎn)擊回調(diào)操作之間運(yùn)行完成了所有的microtasks,相反的是它是在調(diào)用完成了所有的監(jiān)聽回調(diào)后,兩次點(diǎn)擊操作僅僅觸發(fā)了一次mutate。Bug ticket

試試更復(fù)雜的

現(xiàn)在我們僅僅在代碼最后加入一行新的代碼來取代點(diǎn)擊操作:

// Let"s get hold of those elements
var outer = document.querySelector(".outer");
var inner = document.querySelector(".inner");

// Let"s listen for attribute changes on the
// outer element
new MutationObserver(function() {
  console.log("mutate");
}).observe(outer, {
  attributes: true
});

// Here"s a click listener…
function onClick() {
  console.log("click");

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

  Promise.resolve().then(function() {
    console.log("promise");
  });

  outer.setAttribute("data-random", Math.random());
}

// …which we"ll attach to both elements
inner.addEventListener("click", onClick);
outer.addEventListener("click", onClick);


inner.click();

這將會和上一個(gè)例子一樣拋出點(diǎn)擊事件,但我們使用代碼來取代真實(shí)的點(diǎn)擊交互。

試一試

Chrome:
click
click
promise
mutate
promise
timeout
timeout

FireFox:
click
click
mutate
timeout
promise
promise
timeout

Safari:
click
click
mutate
promise
promise
timeout
timeout

Edge:
click
click
mutate
timeout
promise
timeout
promise

為什么會這樣

在所有的監(jiān)聽回調(diào)觸發(fā)完成后…

If the stack of script settings objects is now empty, perform a microtask checkpoint
— HTML: Cleaning up after a callback step 3

在上一個(gè)的例子中,microtasks會在兩個(gè)點(diǎn)擊回調(diào)之間運(yùn)行,但.click()使得兩次事件順序同步執(zhí)行,因此在兩次點(diǎn)擊回調(diào)之間依然存在js代碼在運(yùn)行。而上面的規(guī)則確保了microtasks不會打斷正在執(zhí)行的代碼片段。這意味著我們不能在兩次點(diǎn)擊監(jiān)聽之間執(zhí)行microtasks隊(duì)列,它們將會在監(jiān)聽回調(diào)執(zhí)行完成后開始運(yùn)行。

總結(jié)

Macrotask會順序執(zhí)行,瀏覽器可能會在其執(zhí)行間隔中進(jìn)行渲染操作

Microtask會順序執(zhí)行:

在所有的回調(diào)完成之后,且不存在其他的js代碼正在執(zhí)行

在每一個(gè)macrotask完成之后

希望你現(xiàn)在已經(jīng)清楚了事件循環(huán)的相關(guān)內(nèi)容,或者至少可以去偷個(gè)懶休息一下。

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

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/51616.html

相關(guān)文章

  • 覽器環(huán)境下的microtaksmacrotasks

    摘要:的回調(diào)函數(shù)正是處于隊(duì)列之中。將看做會導(dǎo)致性能問題,回調(diào)函數(shù)可能會因?yàn)殇秩镜认嚓P(guān)產(chǎn)生不必要的延后。瀏覽器是怎么出錯(cuò)的和在兩次點(diǎn)擊操作之間運(yùn)行完成了所有的,就比如的回調(diào)函數(shù)所展示的,但是似乎有不同的排序算法。 帶有可視代碼執(zhí)行順序的原文鏈接https://jakearchibald.com/201...,此篇文字并非其完整翻譯,加入了一部分自己的理解,比如將其中的task替換為macrot...

    FreeZinG 評論0 收藏0
  • Vue nextTixk與任務(wù)

    摘要:以上函數(shù)只有是將回調(diào)放進(jìn)隊(duì)列中,所以是最優(yōu)方案,只有在不存在的情況下才會走其他方法。也是將回調(diào)函數(shù)放進(jìn)中,優(yōu)點(diǎn)是不需要做超時(shí)檢測,目前只有瀏覽器實(shí)現(xiàn)。 js的macrotask和microtask js每次事件循環(huán)只從macrotask中讀取一個(gè)并任務(wù)執(zhí)行,同一個(gè)事件循環(huán)會把microtask中的任務(wù)執(zhí)行完畢并且先于macrotask 為什么要將數(shù)據(jù)更新的處理函數(shù)放在microtask...

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

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

    wanghui 評論0 收藏0
  • 理解javascript中的事件循環(huán)(Event Loop)

    摘要:主線程會暫時(shí)存儲等異步操作,直接向下執(zhí)行,當(dāng)某個(gè)異步事件觸發(fā)時(shí),再通知主線程執(zhí)行相應(yīng)的回調(diào)函數(shù),通過這種機(jī)制,避免了單線程中異步操作耗時(shí)對后續(xù)任務(wù)的影響。 背景 在研究js的異步的實(shí)現(xiàn)方式的時(shí)候,發(fā)現(xiàn)了JavaScript 中的 macrotask 和 microtask 的概念。在查閱了一番資料之后,對其中的執(zhí)行機(jī)制有所了解,下面整理出來,希望可以幫助更多人。 先了解一下js的任務(wù)執(zhí)...

    mykurisu 評論0 收藏0
  • 覽器知識

    摘要:瀏覽器的渲染進(jìn)程是多線程的。異步請求線程在在連接后是通過瀏覽器新開一個(gè)線程請求將檢測到狀態(tài)變更時(shí),如果設(shè)置有回調(diào)函數(shù),異步線程就產(chǎn)生狀態(tài)變更事件,將這個(gè)回調(diào)再放入事件隊(duì)列中。 [TOC] 瀏覽器進(jìn)程線程 區(qū)分線程和進(jìn)程 **- 什么是進(jìn)程** 狹義定義:進(jìn)程是正在運(yùn)行的程序的實(shí)例(an instance of a computer program that is being exe...

    Pluser 評論0 收藏0

發(fā)表評論

0條評論

econi

|高級講師

TA的文章

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