摘要:但是導致了很明顯的性能問題。上述兩個例子其實是在這個中找到的,第一個使用的版本是,這個版本的實現是采用了,而后因為的里的有,于是尤雨溪更改了實現,換成了,也就是后一個所使用的。后來尤雨溪了解到是將回調放入的隊列。
結論
對于event loop 可以抽象成一段簡單的代碼表示
for (macroTask of macroTaskQueue) { // 1. Handle current MACRO-TASK handleMacroTask(); // 2. Handle all MICRO-TASK for (microTask of microTaskQueue) { handleMicroTask(microTask); } }js事件機制
javascript是一個單線程語言,同一時間只能執行一個任務。
對于javascript的事件處理機制,我們可以簡單理解成“主線程+任務隊列”模式。主要步驟如下
(1)所有同步任務都在主線程上執行,形成一個執行棧。任務隊列(2)主線程之外,還存在一個 "任務隊列"(task queue)。只要異步任務有了運行結果,就在 "任務隊列" 之中放置一個事件。
(3)一旦 "執行棧" 中的所有同步任務執行完畢,系統就會讀取 "任務隊列",看看里面有哪些事件。那些對應的異步任務,于是結束等待狀態,進入執行棧,開始執行。(4)主線程不斷重復上面的第三步。
任務隊列分為task queue和microtask queue。執行棧任務清空后會先從Microtasks中取任務,Microtasks中執行完之后才會執行task中的任務。
因此一個event loop主要流程如下:
開始一個Event loop
執行棧從tasks queue中取任務,并執行。
執行完后,執行棧清空
執行棧從microtasks queue中取任務執行
執行完成,執行棧清空
判斷microtasks queue是否還有任務,有則重復步驟3。
進入 Update the rendering(更新渲染)階段
Event loop結束
流程圖如下:
再仔細理解一下開頭列出的代碼:
for (macroTask of macroTaskQueue) { // 1. Handle current MACRO-TASK handleMacroTask(); // 2. Handle all MICRO-TASK for (microTask of microTaskQueue) { handleMicroTask(microTask); } }VUE與EVENT_LOOP 為什么使用Microtask queue
對于VUE這類web2.0框架而言,最主要做的應該還是把對data的修改映射到DOM上。如果只修改一個數據,就刷新一次DOM,那么在一個同步過程中,同時修改好幾個數據,必然會導致多次渲染。這肯定是不可取的。
從上面的event loop我們了解到,一個event loop對應一次render。理想狀況當然就是,一次event loop產生的所有改動最好再render之前將DOM都先更新好。這樣在一個周期中就可以只render一次。
從這點需求出發很容易發現,microtask queue很符合要求。
microtask queue肯定在render ui之前執行完
不像task queue存在多個,microtask只存在一個queue。
最關鍵的是: microtask queue只有都清空了才能進入下一步,無論queue里是什么時候塞進來的。
實際代碼中,不管是鼠標點擊還是鍵盤輸入或是網絡時間,觸發了哪些方法,這些觸發都可以看成開啟一個event loop。這些觸發造成的任何修改都放到microtask queue中,就可以保證在這一輪的evnet loop走到render ui時可以拿到最新的DOM。
要說明的是,這里的render并不是維護虛擬DOM,也不是把虛擬DOM的變化投射到真實DOM上。而是將真實DOM更新到UI的過程。
這么說是因為:Event Loop 并不是在 ECMAScript 標準中定義的,而是在 HTML 標準中定義的:
To coordinate events, user interaction, scripts, rendering, networking, and so forth...
在 JavaScript Engine 中(以 V8 為例),只是實現了 ECMAScript 標準,而并不關心什么 Event Loop。也就是說 Event Loop 是屬于 JavaScript Runtime 的,是由宿主環境提供的(比如瀏覽器)。
瀏覽器可不會關心什么虛擬DOM。只負責DOM改變后渲染UI。
同上: 在開啟一個event loop后,如果將任務放到task queue中,那么這個task任務只會在本輪Event loop結束后才會執行,并開啟新一輪event loop。這無疑會導致兩次render UI。
實際上,尤大為了修復一些bug,曾經將VUE.nexttick用task queue實現。但是導致了很明顯的性能問題。
可以看看兩個列子: 例一 , 例二
兩個fiddle的實現一模一樣,就是讓那個絕對定位的黃色元素起到一個fixed定位的效果:綁定scroll事件,每次滾動的時候,計算當前滾動的位置并更改到那個絕對定位元素的top屬性上去。大家自己試試滾動幾下,對比下效果,你就會發現第一個fiddle中的黃元素是穩定不動的,fixed很好。而后一個fiddle中就有問題了,黃色元素上下晃動,似乎跟不上我們scroll的節奏,總要慢一點,雖然最后停下滾動時位置是對的。
上述兩個例子其實是在這個issue中找到的,第一個jsfiddle使用的版本是Vue 2.0.0-rc.6,這個版本的nextTick實現是采用了MO,而后因為IOS9.3的WebView里的MO有bug,于是尤雨溪更改了實現,換成了window.postMessage,也就是后一個fiddle所使用的Vue 2.0.0-rc.7。后來尤雨溪了解到window.postMessage是將回調放入的macrotask 隊列。這就是問題的根源了。
參考:Tasks, microtasks, queues and schedules
深入理解 JavaScript Event Loop
Vue源碼詳解之nextTick:MutationObserver只是浮云,microtask才是核心!
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/53049.html
摘要:但是導致了很明顯的性能問題。上述兩個例子其實是在這個中找到的,第一個使用的版本是,這個版本的實現是采用了,而后因為的里的有,于是尤雨溪更改了實現,換成了,也就是后一個所使用的。后來尤雨溪了解到是將回調放入的隊列。 結論 對于event loop 可以抽象成一段簡單的代碼表示 for (macroTask of macroTaskQueue) { // 1. Handle cur...
摘要:機制詳解與中實踐應用歸納于筆者的現代開發語法基礎與實踐技巧系列文章。事件循環機制詳解與實踐應用是典型的單線程單并發語言,即表示在同一時間片內其只能執行單個任務或者部分代碼片。 JavaScript Event Loop 機制詳解與 Vue.js 中實踐應用歸納于筆者的現代 JavaScript 開發:語法基礎與實踐技巧系列文章。本文依次介紹了函數調用棧、MacroTask 與 Micr...
摘要:后來尤雨溪了解到是將回調放入的隊列。而且瀏覽器內部為了更快的響應用戶,內部可能是有多個的而的的優先級可能更高,因此對于尤雨溪采用的,甚至可能已經多次執行了的,都沒有執行的,也就導致了我們更新操 原發于我的博客。 前一篇文章已經詳細記述了Vue的核心執行過程。相當于已經搞定了主線劇情。后續的文章都會對其中沒有介紹的細節進行展開。 現在我們就來講講其他支線任務:nextTick和micro...
摘要:整理收藏一些優秀的文章及大佬博客留著慢慢學習原文協作規范中文技術文檔協作規范阮一峰編程風格凹凸實驗室前端代碼規范風格指南這一次,徹底弄懂執行機制一次弄懂徹底解決此類面試問題瀏覽器與的事件循環有何區別筆試題事件循環機制異步編程理解的異步 better-learning 整理收藏一些優秀的文章及大佬博客留著慢慢學習 原文:https://www.ahwgs.cn/youxiuwenzhan...
摘要:事件循環了解知識點線程執行棧線程是單線程的語言可以單線程將理解為只有一條車道在車道里后面的車在等前面的車通過后才能通過即當前面的程序沒有執行后面的程序也不能執行執行棧執行棧像車道被執行的程序會放入執行棧里但它的執行的順序是后面進來的程序先執 事件循環 了解知識點 線程 執行棧 task queue web api macro task micro task 線程 javascrip...
閱讀 3048·2021-11-25 09:43
閱讀 1026·2021-11-24 10:22
閱讀 1352·2021-09-22 15:26
閱讀 681·2019-08-30 15:44
閱讀 2463·2019-08-29 16:33
閱讀 3684·2019-08-26 18:42
閱讀 908·2019-08-23 18:07
閱讀 1832·2019-08-23 17:55