摘要:眾所周知和都屬于上述異步任務的一種那到底為什么和會有順序之分這就是我想分析總結的問題所在了和的作用是為了讓瀏覽器能夠從內部獲取的內容并確保執行棧能夠順序進行。只要執行棧沒有其他在執行,在每個結束時,隊列就會在回調后處理。
前言
我是在做前端面試題中看到了setTimeout和Promise的比較,然后第一次看到了microtask和macrotask的概念,在閱讀了一些文章之后發現沒有一個比較全面易懂的文章,所以我嘗試做一個梳理性的總結.
這道經典的面試題引起了我的興趣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");JavaScript的事件循環機制
首先我們先弄清楚setTimeout和Promise的共同點,也就是我第一次的看到那道面試題的疑惑點.
JavaScript 主線程擁有一個 執行棧 以及一個 任務隊列,主線程會依次執行代碼,當遇到函數時,會先將函數 入棧,函數運行完畢后再將該函數 出棧,直到所有代碼執行完畢。
上面的例子的執行棧執行順序應該是這樣的
console.log("script start"); console.log("script end"); Promise.resolve();
而任務隊列的執行順序應該是這樣的
Promise.then(function() { console.log("promise1"); }); Promise.then(function() { console.log("promise2"); }); setTimeout(function() { console.log("setTimeout"); }, 0);
而主線程則會在 清空當前執行棧后,按照先入先出的順序讀取任務隊列里面的任務。
眾所周知setTimeout和Promise.then()都屬于上述異步任務的一種,那到底為什么setTimeout和Promise.then()會有順序之分,這就是我想分析總結的問題所在了.
macrotasks(tasks) 和 microtasks taskstasks的作用是為了讓瀏覽器能夠從內部獲取javascript / dom的內容并確保執行棧能夠順序進行。
tasks的調度是隨處可見的,例如解析HTML,獲得鼠標點擊的事件回調等等,在這個例子中,我們所迷惑的setTimeout也是一個tasks.
microtasksmicrotasks通常用于在當前正在執行的腳本之后直接發生的事情,比如對一系列的行為做出反應,或者做出一些異步的任務,而不需要新建一個全新的tasks。
只要執行棧沒有其他javascript在執行,在每個tasks結束時,microtasks隊列就會在回調后處理。在microtasks期間排隊的任何其他microtasks將被添加到這個隊列的末尾并進行處理。
microtasks包括mutation observer callbacks,就像上例中的promise callbacks一樣。
所以上面的例子執行順序的實質是tasks =>start end以及resolve
microtasks =>promise1和promise2
tasks =>setTimeout
具體應用需要注意的是,在兩個tasks之間,瀏覽器會重新渲染。這也是我們需要了解tasks和microtasks的一個非常重要的原因.
Vue 中如何使用 MutationObserver 做批量處理? - 顧軼靈的回答 - 知乎瀏覽器兼容問題根據 HTML Standard,在每個 task 運行完以后,UI 都會重渲染,那么在 microtask 中就完成數據更新,當前 task 結束就可以得到最新的 UI 了。反之如果新建一個 task 來做數據更新,那么渲染就會進行兩次。
在__Microsoft Edge__, Firefox 40__, __iOS Safari 以及 desktop Safari 8.0.8 中setTimeout會先于Promise
該例子來自Jake Archibald-->Tasks, microtasks, queues and schedules,其中有動畫來展現tasks和microtasks的具體工作流程,十分推薦閱讀//html
// 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);
在這個例子中,不同瀏覽器的log是不同的,如下所示
Chrome | Firefox | Safari | edge |
---|---|---|---|
click | click | click | click |
promise | mutate | mutate | click |
mutate | click | click | mutate |
click | mutate | mutate | timeout |
promise | timeout | promise | promise |
mutate | promise | promise | timeout |
timeout | promise | timeout | promise |
timeout | timeout | timeout |
事實上Chrome是正確的,而且由此可發現microtasks并不是在tasks的結束階段開始執行,而是在tasks中回調結束之后(只要沒有正在執行的JavaScript代碼)
總結tasks會順序執行,瀏覽器會在執行間隔重新渲染
microtasks會順序執行,執行時機為
在沒有JavaScript代碼執行的callback之后在每一個tasks之后
由于我是前端初學者,對于JavaScript還很不熟悉,對事件循環的進程模型不是很了解,希望這篇文章能夠幫助大家.
事件循環機制建議參考文章
阮一峰-->JavaScript 運行機制詳解:再談Event LoopHTML Living Standard — Last Updated 9 April 2018
tasks建議參考文章
Jake Archibald-->Tasks, microtasks, queues and schedules理解 JavaScript 中的 macrotask 和 microtask
setImmediate.js --A YuzuJS production
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/107676.html
摘要:常見應用則是為了完成一些更新應用程序狀態的較小的任務,如處理的回調和的修改,以便讓這些任務在瀏覽器重新渲染之前執行。常見應用執行順序的實現需要至少一個和至少一個。 簡介 我們在上一篇 《淺析 JS 中的EventLoop 事件循環》 中提到一個 Event Queue,其實在事件循環中 queue 一共有兩種,還有一種叫 Job Queue 其中 Event Queue 在 HTML...
摘要:主線程會暫時存儲等異步操作,直接向下執行,當某個異步事件觸發時,再通知主線程執行相應的回調函數,通過這種機制,避免了單線程中異步操作耗時對后續任務的影響。 背景 在研究js的異步的實現方式的時候,發現了JavaScript 中的 macrotask 和 microtask 的概念。在查閱了一番資料之后,對其中的執行機制有所了解,下面整理出來,希望可以幫助更多人。 先了解一下js的任務執...
摘要:的回調函數正是處于隊列之中。將看做會導致性能問題,回調函數可能會因為渲染等相關產生不必要的延后。瀏覽器是怎么出錯的和在兩次點擊操作之間運行完成了所有的,就比如的回調函數所展示的,但是似乎有不同的排序算法。 帶有可視代碼執行順序的原文鏈接https://jakearchibald.com/201...,此篇文字并非其完整翻譯,加入了一部分自己的理解,比如將其中的task替換為macrot...
摘要:的回調函數正是處于隊列之中。將看做會導致性能問題,回調函數可能會因為渲染等相關產生不必要的延后。瀏覽器是怎么出錯的和在兩次點擊操作之間運行完成了所有的,就比如的回調函數所展示的,但是似乎有不同的排序算法。 帶有可視代碼執行順序的原文鏈接https://jakearchibald.com/201...,此篇文字并非其完整翻譯,加入了一部分自己的理解,比如將其中的task替換為macrot...
前言 我在學習瀏覽器和NodeJS的Event Loop時看了大量的文章,那些文章都寫的很好,但是往往是每篇文章有那么幾個關鍵的點,很多篇文章湊在一起綜合來看,才可以對這些概念有較為深入的理解。 于是,我在看了大量文章之后,想要寫這么一篇博客,不采用官方的描述,結合自己的理解以及示例代碼,用最通俗的語言表達出來。希望大家可以通過這篇文章,了解到Event Loop到底是一種什么機制,瀏覽器和Nod...
閱讀 5739·2021-11-24 10:25
閱讀 2689·2021-11-16 11:44
閱讀 3843·2021-10-11 11:09
閱讀 3172·2021-09-02 15:41
閱讀 3256·2019-08-30 14:14
閱讀 2271·2019-08-29 14:10
閱讀 2345·2019-08-29 11:03
閱讀 1125·2019-08-26 13:47