JS執(zhí)行機制

前言

稀土掘金上看到這一次雳攘,徹底弄懂 JavaScript 執(zhí)行機制從瀏覽器多進程到JS單線程带兜,JS運行機制最全面的一次梳理兩篇關于JS執(zhí)行機制的文章,受益匪淺吨灭,記得剛面試我現(xiàn)在這家公司的時候刚照,面試官就問了我一些執(zhí)行順序的問題,之前沒有系統(tǒng)的總結過喧兄,只用了些事例來回答无畔,最近覺得要系統(tǒng)的梳理之前的積累的一些知識了,先從JS執(zhí)行機制開始吧

javascript特點

js的特點在于它是單線程的吠冤,即同一時間只能做同一件事情浑彰,為什么js不能像java一樣是多線程呢?
主要原因在于應用場景不一樣拯辙,作為瀏覽器腳本語言郭变,更多的是處理DOM的操作和與用戶的交互。假如js創(chuàng)建多線程涯保,一個線程添加一個DOM節(jié)點诉濒,另一個線程刪除當前這個DOM節(jié)點,瀏覽器就無法知道是以那個線程的操作為主了夕春。為了使同步問題變得不那么復雜未荒,在設計之初,js就是按照單線程來設計的及志。h5的API中提出web worker標準茄猫,允許創(chuàng)建多線程狈蚤,但是子線程是受主線程控制的,而且不能操作DOM。

進程和線程

工廠的資源 -> 系統(tǒng)分配的內存(獨立的一塊內存)
工廠之間的相互獨立 -> 進程之間相互獨立
多個工人協(xié)作完成任務 -> 多個線程在進程中協(xié)作完成任務
工廠內有一個或多個工人 -> 一個進程由一個或多個線程組成
工人之間共享空間 -> 同一進程下的各個線程之間共享程序的內存空間(包括代碼段、數(shù)據集躬窜、堆等)

瀏覽器是多進程的
  • 瀏覽器之所以能夠運行啡专,是因為系統(tǒng)給它的進程分配了資源(cpu、內存)
  • 每打開一個Tab頁愉阎,就相當于創(chuàng)建了一個獨立的瀏覽器進程
瀏覽器內核(渲染進程)

如頁面的渲染、js的執(zhí)行、事件的循環(huán)幻捏,瀏覽器的渲染進程是多線程的
主要包括:

  1. GUI渲染線程
  • 負責渲染瀏覽器界面,解析HTML命咐,CSS篡九,構建DOM樹和Render Object樹,布局和繪制等
  • 界面需要重繪(Repaint)或由于某種操作引發(fā)回流(Reflow)時
  • GUI渲染線程和JS引擎線程時互斥的
  1. JS引擎線程
  • JS內核醋奠,負責處理JS腳本程序(V8引擎)
  • JS引擎線程解析js腳本榛臼,運行代碼。
  • JS引擎一直等待著任務隊列中任務的到來窜司,再加以處理沛善,一個Tab頁面(渲染進程)無論什么時候只有一個JS線程再運行JS程序。
  • 如果JS執(zhí)行時間過長塞祈,就會造成頁面的渲染不連貫金刁,導致頁面渲染加載阻塞。
  1. 事件觸發(fā)線程
  • 用于控制事件循環(huán)(JS引擎忙不過來议薪,需要瀏覽器另開線程協(xié)助)
  • 當JS引擎執(zhí)行代碼塊如setTimeOut(也可以來自瀏覽器內核的其他線程尤蛮,如鼠標點擊,ajax異步請求等)會將對應的任務添加到事件線程中
  • 當對應的事件符合觸發(fā)條件被觸發(fā)時斯议,該線程會把事件添加到待處理隊列的隊尾产捞,等待JS引擎的處理
  • JS的單線程關系,這些等待處理隊列中的事件都得排隊等待JS引擎處理完才會執(zhí)行
  1. 定時觸發(fā)器線程
  • setInterval與setTimeout所在線程
  • 瀏覽器定時計數(shù)器并不是由JS引擎計數(shù)的(js引擎是單線程的捅位,如果處于阻塞線程狀態(tài)就會影響計時的準確性)
  • 通過單獨線程來計時并觸發(fā)定時(計時完畢后轧葛,添加到事件隊列中,等待JS引擎空閑后再執(zhí)行)
  • 注意艇搀,W3C在HTML標準中規(guī)定尿扯,規(guī)定要求setTimeout中低于4ms的時間間隔算為4ms
  1. 異步HTTP請求線程
  • 在XMLHTTPRequest在連接后通過瀏覽器新開一個線程請求
  • 將檢測到狀態(tài)變更時,如果設置有回調函數(shù)焰雕,異步線程就產生狀態(tài)變更事件衷笋,將這個回調放入事件隊列中,再由js引擎執(zhí)行矩屁。
    事件循環(huán)機制基于事件觸發(fā)線程的

瀏覽器渲染流程

瀏覽器輸入URL辟宗,瀏覽器主進程接管爵赵,開啟一個下載線程
DNS查詢
IP尋址
HTTP請求
等待響應,獲取內容
將內容通過RendererHost接口轉交給Renderer進程
瀏覽器渲染流程開始

瀏覽器內核拿到內容后泊脐,渲染大概分成以下步驟:

  1. 解析html建立dom樹
    2.解析css構建render樹(將CSS代碼解析成樹形的數(shù)據結構空幻,然后結合DOM合成render樹)
    3.布局render樹(layout/reflow),負責各元素尺寸,位置的計算
    4.繪制render樹容客,繪制頁面像素信息
    5.瀏覽器會將各層的信息發(fā)送給GPU秕铛,GPU會將各層合成,顯示在屏幕上

Event Loop談JS的運行機制

  • JS分成同步任務和異步任務
  • 同步任務都在主線程上執(zhí)行缩挑,形成一個執(zhí)行棧
  • 主線程外但两,事件觸發(fā)線程管理一個任務隊列,只要有異步任務有了運行結果供置,就在任務隊列中放置一個事件
  • 一旦執(zhí)行棧中所有的同步任務執(zhí)行完成(JS引擎空閑)谨湘,系統(tǒng)會讀取任務隊列,將可運行的異步任務添加到可執(zhí)行棧中芥丧,開始執(zhí)行
    應該就可以理解了:為什么有時候setTimeout推入的事件不能準時執(zhí)行紧阔?因為可能在它推入到事件列表時,主線程還不空閑娄柳,正在執(zhí)行其它代碼寓辱, 所以自然有誤差

時間循環(huán):macrotask與microtask

  • 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快蕉朵,因為無需等待渲染
  • 在某個macrotask執(zhí)行完后,就會將在他執(zhí)行期間產生的所有microtask都執(zhí)行完畢(在渲染前)
    macrotask:主代碼塊阳掐,setTimeout始衅、setInterval、MessageChannel缭保、postMessage汛闸、setImmediate等(事件隊列中的每一個事件都是一個macrotask)
    microtask: MutationObsever 、Promise.then艺骂、process.nextTick等
    根據線程理解:
  • macrotask中的事件都是放在一個事件隊列中的诸老,而這個隊列由事件觸發(fā)線程維護
  • microtask中的微任務都是添加到微任務隊列中,等待當前macrotask執(zhí)行完畢后執(zhí)行钳恕,這個隊列由JS引擎線程維護(在主線程下無縫執(zhí)行的)
    運行機制:
  • 執(zhí)行一個宏任務(棧中沒有就從事件隊列中獲缺鸱)
  • 執(zhí)行過程中如果遇到微任務蹄衷,就 添加到微任務的任務隊列中
  • 宏任務執(zhí)行完畢后,立即執(zhí)行當前微任務隊列中的所有微任務
  • 當前宏任務執(zhí)行完畢后厘肮,開始檢查渲染愧口,然后GUI線程接管渲染
  • 渲染完畢后,JS線程繼續(xù)接管类茂,開始下一個宏任務(從事件隊列中獲鹊鞅啊)
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市大咱,隨后出現(xiàn)的幾起案子恬涧,更是在濱河造成了極大的恐慌,老刑警劉巖碴巾,帶你破解...
    沈念sama閱讀 211,265評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件溯捆,死亡現(xiàn)場離奇詭異,居然都是意外死亡厦瓢,警方通過查閱死者的電腦和手機提揍,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評論 2 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來煮仇,“玉大人劳跃,你說我怎么就攤上這事≌愕妫” “怎么了刨仑?”我有些...
    開封第一講書人閱讀 156,852評論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長夹姥。 經常有香客問我杉武,道長,這世上最難降的妖魔是什么辙售? 我笑而不...
    開封第一講書人閱讀 56,408評論 1 283
  • 正文 為了忘掉前任轻抱,我火速辦了婚禮,結果婚禮上旦部,老公的妹妹穿的比我還像新娘祈搜。我一直安慰自己,他們只是感情好士八,可當我...
    茶點故事閱讀 65,445評論 5 384
  • 文/花漫 我一把揭開白布容燕。 她就那樣靜靜地躺著,像睡著了一般曹铃。 火紅的嫁衣襯著肌膚如雪缰趋。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,772評論 1 290
  • 那天,我揣著相機與錄音秘血,去河邊找鬼味抖。 笑死,一個胖子當著我的面吹牛灰粮,可吹牛的內容都是我干的仔涩。 我是一名探鬼主播,決...
    沈念sama閱讀 38,921評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼粘舟,長吁一口氣:“原來是場噩夢啊……” “哼熔脂!你這毒婦竟也來了?” 一聲冷哼從身側響起柑肴,我...
    開封第一講書人閱讀 37,688評論 0 266
  • 序言:老撾萬榮一對情侶失蹤霞揉,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后晰骑,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體适秩,經...
    沈念sama閱讀 44,130評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,467評論 2 325
  • 正文 我和宋清朗相戀三年硕舆,在試婚紗的時候發(fā)現(xiàn)自己被綠了秽荞。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,617評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡抚官,死狀恐怖扬跋,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情凌节,我是刑警寧澤钦听,帶...
    沈念sama閱讀 34,276評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站刊咳,受9級特大地震影響彪见,放射性物質發(fā)生泄漏儡司。R本人自食惡果不足惜娱挨,卻給世界環(huán)境...
    茶點故事閱讀 39,882評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望捕犬。 院中可真熱鬧跷坝,春花似錦、人聲如沸碉碉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽垢粮。三九已至贴届,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背毫蚓。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評論 1 265
  • 我被黑心中介騙來泰國打工占键, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人元潘。 一個月前我還...
    沈念sama閱讀 46,315評論 2 360
  • 正文 我出身青樓畔乙,卻偏偏與公主長得像,于是被迫代替她去往敵國和親翩概。 傳聞我的和親對象是個殘疾皇子牲距,可洞房花燭夜當晚...
    茶點故事閱讀 43,486評論 2 348

推薦閱讀更多精彩內容