從瀏覽器多進程到JS單線程

timg (1).jpg

前言


最近發(fā)現(xiàn)有不少介紹JS單線程運行機制的文章拴泌,但是發(fā)現(xiàn)很多都僅僅是介紹某一部分的知識,而且各個地方的說法還不統(tǒng)一惊橱,容易造成困惑蚪腐。
因此準備梳理這塊知識點,結合已有的認知税朴,基于網(wǎng)上的大量參考資料削茁,
從瀏覽器多進程到JS單線程,將JS引擎的運行機制系統(tǒng)的梳理一遍掉房。

內容是:從瀏覽器進程茧跋,再到瀏覽器內核運行,再到JS引擎單線程卓囚,再到JS事件循環(huán)機制瘾杭,從頭到尾系統(tǒng)的梳理一遍,擺脫碎片化哪亿,形成一個知識體系

目標是:看完這篇文章后粥烁,對瀏覽器多進程,JS單線程蝇棉,JS事件循環(huán)機制這些都能有一定理解讨阻,
有一個知識體系骨架,而不是似懂非懂的感覺篡殷。

另外钝吮,本文適合有一定經(jīng)驗的前端人員,新手請規(guī)避板辽,避免受到過多的概念沖擊奇瘦。可以先存起來劲弦,有了一定理解后再看耳标,也可以分成多批次觀看,避免過度疲勞邑跪。見解有限次坡,如有描述不當之處,請幫忙及時指出画畅,如有錯誤砸琅,會及時修正。

框架總覽


  • ?? 區(qū)分進程和線程
  • ?? 瀏覽器是多進程的
  • ?? 瀏覽器都包含哪些進程夜赵?
  • ?? 瀏覽器渲染進程
  • ?? Browser進程和瀏覽器內核(Renderer進程)的通信過程
  • ??梳理瀏覽器內核中線程之間的關系
  • ?? 簡單梳理下瀏覽器渲染流程
  • ?? 從Event Loop談JS的運行機制
  • ?? 單獨說說定時器
  • ?? setTimeout而不是setInterval
  • ?? 事件循環(huán)進階:macrotask與microtask

區(qū)分進程和線程

線程和進程區(qū)分不清明棍,是很多新手都會犯的錯誤,沒有關系寇僧。這很正常摊腋。先看看下面這個形象的比喻:

- 進程是一個工廠沸版,工廠有它的獨立資源

- 工廠之間相互獨立

- 線程是工廠中的工人,多個工人協(xié)作完成任務

- 工廠內有一個或多個工人

- 工人之間共享空間

然后再鞏固下:

如果是windows電腦中兴蒸,可以打開任務管理器视粮,可以看到有一個后臺進程列表。對橙凳,那里就是查看進程的地方蕾殴,而且可以看到每個進程的內存資源信息以及cpu占有率。


image.png

所以岛啸,應該更容易理解了:

  • 進程是cpu資源分配的最小單位(系統(tǒng)會給它分配內存)
  • 線程是cpu調度的最小單位(線程是建立在進程的基礎上的一次程序運行計算钓觉,一個進程中可以有多個線程)

tips

  • 不同進程之間也可以通信,不過代價較大
  • 現(xiàn)在坚踩,一般通用的叫法:單線程與多線程荡灾,都是指在一個進程內的單和多。(所以核心還是得屬于一個進程才行)

瀏覽器是多進程的

理解了進程與線程了區(qū)別后瞬铸,接下來對瀏覽器進行一定程度上的認識:(先看下簡化理解)

  • 瀏覽器是多進程的
  • 瀏覽器之所以能夠運行批幌,是因為系統(tǒng)給它的進程分配了資源(cpu、內存)
  • 簡單點理解嗓节,每打開一個Tab頁荧缘,就相當于創(chuàng)建了一個獨立的瀏覽器進程。

關于以上幾點的驗證拦宣,請再第一張圖

image.png

圖中打開了Chrome瀏覽器的多個標簽頁截粗,然后可以在Chrome的任務管理器中看到有多個進程(分別是每一個Tab頁面有一個獨立的進程,以及一個主進程)恢着。
感興趣的可以自行嘗試下桐愉,如果再多打開一個Tab頁财破,進程正常會+1以上

注意:在這里瀏覽器應該也有自己的優(yōu)化機制掰派,有時候打開多個tab頁后,可以在Chrome任務管理器中看到左痢,有些進程被合并了
(所以每一個Tab標簽對應一個進程并不一定是絕對的)

瀏覽器都包含哪些進程靡羡?

知道了瀏覽器是多進程后,再來看看它到底包含哪些進程:(為了簡化理解俊性,僅列舉主要進程)

  1. Browser進程:瀏覽器的主進程(負責協(xié)調略步、主控),只有一個定页。作用有

    • 負責瀏覽器界面顯示趟薄,與用戶交互。如前進典徊,后退等
    • 負責各個頁面的管理杭煎,創(chuàng)建和銷毀其他進程
    • 將瀏覽器渲染進程得到的內存中的Bitmap恩够,繪制到用戶界面上
    • 網(wǎng)絡資源的管理,下載等
  2. 第三方插件進程:每種類型的插件對應一個進程羡铲,僅當使用該插件時才創(chuàng)建

  3. GPU進程:最多一個蜂桶,用于3D繪制等

  4. 瀏覽器渲染進程(Renderer進程,內部是多線程的):默認每個Tab頁面一個進程也切,互不影響扑媚。主要作用為
    頁面渲染,腳本執(zhí)行雷恃,事件處理等

強化記憶:在瀏覽器中打開一個網(wǎng)頁相當于新起了一個進程(進程內有自己的多線程)
如果瀏覽器是單進程疆股,那么某個Tab頁崩潰了,就影響了整個瀏覽器倒槐,體驗有多差押桃;同理如果是單進程,插件崩潰了也會影響整個瀏覽器导犹;而且多進程還有其它的諸多優(yōu)勢唱凯。。谎痢。

當然磕昼,瀏覽器有時會將多個進程合并(譬如打開多個空白標簽頁后,會發(fā)現(xiàn)多個空白標簽頁被合并成了一個進程)节猿,如圖

image.png

另外票从,可以通過Chrome的更多工具 -> 任務管理器自行驗證。接下來重點講瀏覽器渲染進程滨嘱。

瀏覽器渲染進程

重點來了峰鄙,我們可以看到,上面提到了這么多的進程太雨,那么吟榴,對于普通的前端操作來說,最重要的是什么呢囊扳?答案是瀏覽器渲染進程

可以這樣理解吩翻,頁面的渲染,JS的執(zhí)行锥咸,事件的循環(huán)狭瞎,都在這個進程內進行。接下來看看它都包含了哪些線程(列舉一些主要常駐線程):

  1. GUI渲染線程

    • 負責渲染瀏覽器界面搏予,解析HTML熊锭,CSS,構建DOM樹和RenderObject樹,布局和繪制等碗殷。
    • 當界面需要重繪(Repaint)或由于某種操作引發(fā)回流(reflow)時劣针,該線程就會執(zhí)行
    • 注意,GUI渲染線程與JS引擎線程是互斥的亿扁,當JS引擎執(zhí)行時GUI線程會被掛起(相當于被凍結了)捺典,GUI更新會被保存在一個隊列中等到JS引擎空閑時立即被執(zhí)行。
  2. JS引擎線程

    • 也稱為JS內核从祝,負責處理Javascript腳本程序襟己。(例如V8引擎)
    • JS引擎線程負責解析Javascript腳本,運行代碼牍陌。
    • JS引擎一直等待著任務隊列中任務的到來擎浴,然后加以處理,一個Tab頁(renderer進程)中無論什么時候都只有一個JS線程在運行JS程序
    • 同樣注意毒涧,GUI渲染線程與JS引擎線程是互斥的贮预,所以如果JS執(zhí)行的時間過長,這樣就會造成頁面的渲染不連貫契讲,導致頁面渲染加載阻塞仿吞。
  3. 事件觸發(fā)線程

    • 歸屬于瀏覽器而不是JS引擎,用來控制事件循環(huán)(可以理解捡偏,JS引擎自己都忙不過來唤冈,需要瀏覽器另開線程協(xié)助)
    • 當JS引擎執(zhí)行代碼塊如setTimeOut時(也可來自瀏覽器內核的其他線程,如鼠標點擊、AJAX異步請求等)银伟,會將對應任務添加到事件線程中
    • 當對應的事件符合觸發(fā)條件被觸發(fā)時你虹,該線程會把事件添加到待處理隊列的隊尾,等待JS引擎的處理
    • 注意彤避,由于JS的單線程關系傅物,所以這些待處理隊列中的事件都得排隊等待JS引擎處理(當JS引擎空閑時才會去執(zhí)行)
  4. 定時觸發(fā)器線程

    • 傳說中的setIntervalsetTimeout所在線程
    • 瀏覽器定時計數(shù)器并不是由JavaScript引擎計數(shù)的,(因為JavaScript引擎是單線程的, 如果處于阻塞線程狀態(tài)就會影響記計時的準確)
    • 因此通過單獨線程來計時并觸發(fā)定時(計時完畢后,添加到事件隊列中琉预,等待JS引擎空閑后執(zhí)行)
    • 注意董饰,W3C在HTML標準中規(guī)定,規(guī)定要求setTimeout中低于4ms的時間間隔算為4ms模孩。
  5. 異步http請求線程

    • 在XMLHttpRequest在連接后是通過瀏覽器新開一個線程請求
    • 將檢測到狀態(tài)變更時尖阔,如果設置有回調函數(shù),異步線程就產(chǎn)生狀態(tài)變更事件榨咐,將這個回調再放入事件隊列中。再由JavaScript引擎執(zhí)行谴供。

看到這里块茁,如果覺得累了,可以先休息下,這些概念需要被消化畜挥,畢竟后續(xù)將提到的事件循環(huán)機制就是基于事件觸發(fā)線程的抠忘,所以如果僅僅是看某個碎片化知識健爬,
可能會有一種似懂非懂的感覺。要完成的梳理一遍才能快速沉淀遂蛀,不易遺忘。放張圖鞏固下吧:

2084336019-5a65972413011_articlex.png

Browser進程和瀏覽器內核(Renderer進程)的通信過程

看到這里干厚,首先李滴,應該對瀏覽器內的進程和線程都有一定理解了,那么接下來蛮瞄,再談談瀏覽器的Browser進程(控制進程)是如何和內核通信的所坯,
這點也理解后,就可以將這部分的知識串聯(lián)起來挂捅,從頭到尾有一個完整的概念芹助。

如果自己打開任務管理器,然后打開一個瀏覽器闲先,就可以看到:任務管理器中出現(xiàn)了兩個進程(一個是主控進程状土,一個則是打開Tab頁的渲染進程)
然后在這前提下伺糠,看下整個的過程:(簡化了很多)

  • Browser進程收到用戶請求声诸,首先需要獲取頁面內容(譬如通過網(wǎng)絡下載資源),隨后將該任務通過RendererHost接口傳遞給Render進程

  • Renderer進程的Renderer接口收到消息退盯,簡單解釋后彼乌,交給渲染線程,然后開始渲染

    • 渲染線程接收請求渊迁,加載網(wǎng)頁并渲染網(wǎng)頁慰照,這其中可能需要Browser進程獲取資源和需要GPU進程來幫助渲染
    • 當然可能會有JS線程操作DOM(這樣可能會造成回流并重繪)
    • 最后Render進程將結果傳遞給Browser進程
  • Browser進程接收到結果并將結果繪制出來

看完這一整套流程,應該對瀏覽器的運作有了一定理解了琉朽,這樣有了知識架構的基礎后毒租,后續(xù)就方便往上填充內容。

梳理瀏覽器內核中線程之間的關系

到了這里箱叁,已經(jīng)對瀏覽器的運行有了一個整體的概念墅垮,接下來,先簡單梳理一些概念

GUI渲染線程與JS引擎線程互斥

由于JavaScript是可操縱DOM的耕漱,如果在修改這些元素屬性同時渲染界面(即JS線程和UI線程同時運行)算色,那么渲染線程前后獲得的元素數(shù)據(jù)就可能不一致了。

因此為了防止渲染出現(xiàn)不可預期的結果螟够,瀏覽器設置GUI渲染線程與JS引擎為互斥的關系灾梦,當JS引擎執(zhí)行時GUI線程會被掛起峡钓,
GUI更新則會被保存在一個隊列中等到JS引擎線程空閑時立即被執(zhí)行。

JS阻塞頁面加載

從上述的互斥關系若河,可以推導出能岩,JS如果執(zhí)行時間過長就會阻塞頁面。

譬如萧福,假設JS引擎正在進行巨量的計算拉鹃,此時就算GUI有更新,也會被保存到隊列中鲫忍,等待JS引擎空閑后執(zhí)行膏燕。
然后,由于巨量計算饲窿,所以JS引擎很可能很久很久后才能空閑煌寇,自然會感覺到巨卡無比。

所以逾雄,要盡量避免JS執(zhí)行時間過長阀溶,這樣就會造成頁面的渲染不連貫,導致頁面渲染加載阻塞的感覺鸦泳。

簡單梳理下瀏覽器渲染流程

本來是直接計劃開始談JS運行機制的银锻,但想了想,既然上述都一直在談瀏覽器做鹰,直接跳到JS可能再突兀击纬,因此,中間再補充下瀏覽器的渲染流程(簡單版本)

為了簡化理解钾麸,前期工作直接省略成:(要展開的或完全可以寫另一篇超長文)

- 瀏覽器輸入url更振,瀏覽器主進程接管,開一個下載線程饭尝,
然后進行 http請求(略去DNS查詢肯腕,IP尋址等等操作),然后等待響應钥平,獲取內容实撒,
隨后將內容通過RendererHost接口轉交給Renderer進程

- 瀏覽器渲染流程開始

瀏覽器器內核拿到內容后,渲染大概可以劃分成以下幾個步驟:

  1. 解析html建立dom樹
  2. 解析css構建render樹(將CSS代碼解析成樹形的數(shù)據(jù)結構涉瘾,然后結合DOM合并成render樹)
  3. 布局render樹(Layout/reflow)知态,負責各元素尺寸、位置的計算
  4. 繪制render樹(paint)立叛,繪制頁面像素信息
  5. 瀏覽器會將各層的信息發(fā)送給GPU负敏,GPU會將各層合成(composite),顯示在屏幕上囚巴。

所有詳細步驟都已經(jīng)略去原在,渲染完畢后就是load事件了友扰,之后就是自己的JS邏輯處理了

既然略去了一些詳細的步驟彤叉,那么就提一些可能需要注意的細節(jié)把庶柿。

這里重繪參考來源中的一張圖:


1373095523-5a658fc12f1fd_articlex.png

從Event Loop談JS的運行機制

到此時,已經(jīng)是屬于瀏覽器頁面初次渲染完畢后的事情秽浇,JS引擎的一些運行機制分析浮庐。

注意,這里不談可執(zhí)行上下文柬焕,VO审残,scop chain等概念(這些完全可以整理成另一篇文章了),這里主要是結合Event Loop來談JS代碼是如何執(zhí)行的斑举。

讀這部分的前提是已經(jīng)知道了JS引擎是單線程搅轿,而且這里會用到上文中的幾個概念:(如果不是很理解,可以回頭溫習)

  • JS引擎線程
  • 事件觸發(fā)線程
  • 定時觸發(fā)器線程

然后再理解一個概念:

  • JS分為同步任務和異步任務
  • 同步任務都在主線程上執(zhí)行富玷,形成一個執(zhí)行棧
  • 主線程之外璧坟,事件觸發(fā)線程管理著一個任務隊列,只要異步任務有了運行結果赎懦,就在任務隊列之中放置一個事件雀鹃。定時器觸發(fā)線程也管理著一個任務隊列,定時器線程控制特定時間后將回調函數(shù)添加到任務隊列励两。同理黎茎,http異步請求線程也會將請求結果的回調函數(shù)添加到任務隊列中。
  • 一旦執(zhí)行棧中的所有同步任務執(zhí)行完畢(此時JS引擎空閑)当悔,系統(tǒng)就會讀取任務隊列傅瞻,將可運行的異步任務添加到可執(zhí)行棧中,開始執(zhí)行盲憎。

看圖:

3521345917-5a659722efdc2_articlex.png

tips:看到這里嗅骄,應該就可以理解了:為什么有時候setTimeout推入的事件不能準時執(zhí)行?因為可能在它推入到事件列表時焙畔,主線程還不空閑掸读,正在執(zhí)行其它代碼,所以自然有誤差宏多。

事件循環(huán)機制進一步補充

這里就直接引用一張圖片來協(xié)助理解:(參考自Philip Roberts的演講《Help, I'm stuck in an event-loop》)

1103131299-5a659722e7a98_articlex.png

上圖大致描述就是:

  • 主線程運行時會產(chǎn)生執(zhí)行棧儿惫,

棧中的代碼調用某些api時,它們會在事件隊列中添加各種事件(當滿足觸發(fā)條件后伸但,如ajax請求完畢)

  • 而棧中的代碼執(zhí)行完畢肾请,就會讀取事件隊列中的事件,去執(zhí)行那些回調
  • 如此循環(huán)
  • 注意更胖,總是要等待棧中的代碼執(zhí)行完畢后才會去讀取事件隊列中的事件

單獨說說定時器

上述事件循環(huán)機制的核心是:JS引擎線程和事件觸發(fā)線程

但事件上铛铁,里面還有一些隱藏細節(jié)隔显,譬如調用setTimeout后,是如何等待特定時間后才添加到事件隊列中的饵逐?

是JS引擎檢測的么括眠?當然不是了。它是由定時器線程控制(因為JS引擎自己都忙不過來倍权,根本無暇分身)

為什么要單獨的定時器線程掷豺?因為JavaScript引擎是單線程的, 如果處于阻塞線程狀態(tài)就會影響記計時的準確,因此很有必要單獨開一個線程用來計時薄声。

什么時候會用到定時器線程当船?當使用setTimeoutsetInterval,它需要定時器線程計時默辨,計時完成后就會將特定的事件推入事件隊列中德频。

譬如:

setTimeout(function(){
    console.log('hello!');
}, 1000);

這段代碼的作用是當1000毫秒計時完畢后(由定時器線程計時),將回調函數(shù)推入事件隊列中缩幸,等待主線程執(zhí)行

setTimeout(function(){
    console.log('hello!');
}, 0);

console.log('begin');

這段代碼的效果是最快的時間內將回調函數(shù)推入事件隊列中壹置,等待主線程執(zhí)行

注意:

  • 執(zhí)行結果是:先beginhello!
  • 雖然代碼的本意是0毫秒后就推入事件隊列,但是W3C在HTML標準中規(guī)定桌粉,規(guī)定要求setTimeout中低于4ms的時間間隔算為4ms蒸绩。

(不過也有一說是不同瀏覽器有不同的最小時間設定)

  • 就算不等待4ms,就算假設0毫秒就推入事件隊列铃肯,也會先執(zhí)行begin(因為只有可執(zhí)行棧內空了后才會主動讀取事件隊列)

setTimeout而不是setInterval

用setTimeout模擬定期計時和直接用setInterval是有區(qū)別的患亿。

因為每次setTimeout計時到后就會去執(zhí)行,然后執(zhí)行一段時間后才會繼續(xù)setTimeout押逼,中間就多了誤差
(誤差多少與代碼執(zhí)行時間有關)

而setInterval則是每次都精確的隔一段時間推入一個事件
(但是步藕,事件的實際執(zhí)行時間不一定就準確,還有可能是這個事件還沒執(zhí)行完畢挑格,下一個事件就來了)

而且setInterval有一些比較致命的問題就是:

  • 累計效應(上面提到的)咙冗,如果setInterval代碼在(setInterval)再次添加到隊列之前還沒有完成執(zhí)行,

就會導致定時器代碼連續(xù)運行好幾次漂彤,而之間沒有間隔雾消。
就算正常間隔執(zhí)行,多個setInterval的代碼執(zhí)行時間可能會比預期写焱(因為代碼執(zhí)行需要一定時間)

  • 譬如像iOS的webview,或者Safari等瀏覽器中都有一個特點立润,在滾動的時候是不執(zhí)行JS的,如果使用了setInterval媳板,會發(fā)現(xiàn)在滾動結束后會執(zhí)行多次由于滾動不執(zhí)行JS積攢回調桑腮,如果回調執(zhí)行時間過長,就會非常容器造成卡頓問題和一些不可知的錯誤(這一塊后續(xù)有補充,setInterval自帶的優(yōu)化蛉幸,不會重復添加回調)
  • 而且把瀏覽器最小化顯示等操作時破讨,setInterval并不是不執(zhí)行程序丛晦,

它會把setInterval的回調函數(shù)放在隊列中,等瀏覽器窗口再次打開時提陶,一瞬間全部執(zhí)行時

所以烫沙,鑒于這么多但問題,目前一般認為的最佳方案是:用setTimeout模擬setInterval搁骑,或者特殊場合直接用requestAnimationFrame

補充:JS高程中有提到斧吐,JS引擎會對setInterval進行優(yōu)化又固,如果當前事件隊列中有setInterval的回調仲器,不會重復添加。不過仰冠,仍然是有很多問題乏冀。。洋只。

事件循環(huán)進階:macrotask與microtask

這段參考了參考來源中的第2篇文章(英文版的)辆沦,(加了下自己的理解重新描述了下),
強烈推薦有英文基礎的同學直接觀看原文识虚,作者描述的很清晰肢扯,示例也很不錯,如下:

https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/

上文中將JS事件循環(huán)機制梳理了一遍担锤,在ES5的情況是夠用了蔚晨,但是在ES6盛行的現(xiàn)在,仍然會遇到一些問題肛循,譬如下面這題:

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');

嗯哼铭腕,它的正確執(zhí)行順序是這樣子的:

script start
script end
promise1
promise2
setTimeout

為什么呢?因為Promise里有了一個一個新的概念:microtask

或者多糠,進一步累舷,JS中分為兩種任務類型:macrotaskmicrotask,在ECMAScript中夹孔,microtask稱為jobs被盈,macrotask可稱為task

它們的定義?區(qū)別搭伤?簡單點可以按如下理解:

  • macrotask(又稱之為宏任務)只怎,可以理解是每次執(zhí)行棧執(zhí)行的代碼就是一個宏任務(包括每次從事件隊列中獲取一個事件回調并放到執(zhí)行棧中執(zhí)行)

    • 每一個task會從頭到尾將這個任務執(zhí)行完畢,不會執(zhí)行其它
    • 瀏覽器為了能夠使得JS內部task與DOM任務能夠有序的執(zhí)行闷畸,會在一個task執(zhí)行結束后尝盼,在下一個 task 執(zhí)行開始前,對頁面進行重新渲染
(`task->渲染->task->...`)

  • microtask(又稱為微任務)佑菩,可以理解是在當前 task 執(zhí)行結束后立即執(zhí)行的任務

    • 也就是說盾沫,在當前task任務后裁赠,下一個task之前,在渲染之前
    • 所以它的響應速度相比setTimeout(setTimeout是task)會更快赴精,因為無需等渲染
    • 也就是說佩捞,在某一個macrotask執(zhí)行完后,就會將在它執(zhí)行期間產(chǎn)生的所有microtask都執(zhí)行完畢蕾哟,微任務包含微任務的一忱,會把這個任務放到本輪循環(huán)的尾部執(zhí)行。

分別怎么樣樣的場景會形成macrotask和microtask呢谭确?

  • macrotask:主代碼塊帘营,setTimeout,setInterval等(可以看到逐哈,事件隊列中的每一個事件都是一個macrotask)
  • microtask:Promise芬迄,process.nextTick等

補充:在node環(huán)境下,process.nextTick的優(yōu)先級高于Promise昂秃,也就是可以簡單理解為:在宏任務結束后會先執(zhí)行微任務隊列中的nextTickQueue部分禀梳,然后才會執(zhí)行微任務中的Promise部分。

參考:https://segmentfault.com/q/1010000011914016

再根據(jù)線程來理解下:

  • macrotask中的事件都是放在一個事件隊列中的肠骆,而這個隊列由事件觸發(fā)線程維護
  • microtask中的所有微任務都是添加到微任務隊列(Job Queues)中算途,等待當前macrotask執(zhí)行完畢后執(zhí)行,而這個隊列由JS引擎線程維護

(這點由自己理解+推測得出蚀腿,因為它是在主線程下無縫執(zhí)行的)

所以嘴瓤,總結下運行機制:

  • 執(zhí)行一個宏任務(棧中沒有就從事件隊列中獲取)
  • 執(zhí)行過程中如果遇到微任務唯咬,就將它添加到微任務的任務隊列中纱注,微任務嵌套微任務的就把這個任務放到當前隊列尾部
  • 宏任務執(zhí)行完畢后,立即執(zhí)行當前微任務隊列中的所有微任務(依次執(zhí)行)
  • 當前宏任務執(zhí)行完畢胆胰,開始檢查渲染狞贱,然后GUI線程接管渲染
  • 渲染完畢后,JS線程繼續(xù)接管蜀涨,開始下一個宏任務(從事件隊列中獲认规摇)

如圖:

3521345917-5a659722efdc2_articlex.png

由于js引擎線程和GUI線程是互斥的,當j瀏覽器js執(zhí)行時間過長將會造成頁面卡頓厚柳,不能及時響應用戶的交互氧枣。所以。React Fiber給出了解決方案别垮。下一篇文章將會著重講一下便监。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子烧董,更是在濱河造成了極大的恐慌毁靶,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,110評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件逊移,死亡現(xiàn)場離奇詭異预吆,居然都是意外死亡,警方通過查閱死者的電腦和手機胳泉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評論 3 395
  • 文/潘曉璐 我一進店門拐叉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人扇商,你說我怎么就攤上這事凤瘦。” “怎么了钳吟?”我有些...
    開封第一講書人閱讀 165,474評論 0 356
  • 文/不壞的土叔 我叫張陵廷粒,是天一觀的道長。 經(jīng)常有香客問我红且,道長,這世上最難降的妖魔是什么涤姊? 我笑而不...
    開封第一講書人閱讀 58,881評論 1 295
  • 正文 為了忘掉前任暇番,我火速辦了婚禮,結果婚禮上思喊,老公的妹妹穿的比我還像新娘壁酬。我一直安慰自己,他們只是感情好恨课,可當我...
    茶點故事閱讀 67,902評論 6 392
  • 文/花漫 我一把揭開白布舆乔。 她就那樣靜靜地躺著,像睡著了一般剂公。 火紅的嫁衣襯著肌膚如雪希俩。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,698評論 1 305
  • 那天纲辽,我揣著相機與錄音颜武,去河邊找鬼。 笑死拖吼,一個胖子當著我的面吹牛鳞上,可吹牛的內容都是我干的。 我是一名探鬼主播吊档,決...
    沈念sama閱讀 40,418評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼篙议,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了怠硼?” 一聲冷哼從身側響起鬼贱,我...
    開封第一講書人閱讀 39,332評論 0 276
  • 序言:老撾萬榮一對情侶失蹤趾断,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后吩愧,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體芋酌,經(jīng)...
    沈念sama閱讀 45,796評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,968評論 3 337
  • 正文 我和宋清朗相戀三年雁佳,在試婚紗的時候發(fā)現(xiàn)自己被綠了脐帝。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,110評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡糖权,死狀恐怖堵腹,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情星澳,我是刑警寧澤疚顷,帶...
    沈念sama閱讀 35,792評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站禁偎,受9級特大地震影響腿堤,放射性物質發(fā)生泄漏。R本人自食惡果不足惜如暖,卻給世界環(huán)境...
    茶點故事閱讀 41,455評論 3 331
  • 文/蒙蒙 一笆檀、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧盒至,春花似錦酗洒、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,003評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至酒唉,卻和暖如春矩桂,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背黔州。 一陣腳步聲響...
    開封第一講書人閱讀 33,130評論 1 272
  • 我被黑心中介騙來泰國打工耍鬓, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人流妻。 一個月前我還...
    沈念sama閱讀 48,348評論 3 373
  • 正文 我出身青樓牲蜀,卻偏偏與公主長得像,于是被迫代替她去往敵國和親绅这。 傳聞我的和親對象是個殘疾皇子涣达,可洞房花燭夜當晚...
    茶點故事閱讀 45,047評論 2 355