自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

JavaScript內(nèi)部原理:瀏覽器的內(nèi)幕

開發(fā) 前端
了解瀏覽器環(huán)境,它的組成以及它的工作原理會(huì)讓我們?cè)诰帉?JS 時(shí)更加自信,并為可能發(fā)生的潛在問題做好了充分的準(zhǔn)備。在這篇文章中,我們?cè)囍忉屢幌翪hrome瀏覽器下到底發(fā)生了什么。

簡介

Javascript 是一種奇怪語言,有些人喜歡它,有些人討厭它。它有許多獨(dú)特的機(jī)制,這些機(jī)制在其他流行語言中不存在,也沒有對(duì)應(yīng)的機(jī)制,還有突出明顯的就是代碼的執(zhí)行順序。

了解瀏覽器環(huán)境,它的組成以及它的工作原理會(huì)讓我們?cè)诰帉?JS 時(shí)更加自信,并為可能發(fā)生的潛在問題做好了充分的準(zhǔn)備。

[[318401]]

在這篇文章中,我們?cè)囍忉屢幌翪hrome瀏覽器下到底發(fā)生了什么,來一起看看:

  • V8 Javascript 引擎編譯步驟,堆和內(nèi)存管理,調(diào)用堆棧。
  • 瀏覽器運(yùn)行時(shí)并發(fā)模型、事件循環(huán)、阻塞和非阻塞代碼。

JavaScript引擎

最流行的JavaScript引擎是V8,它是用c++編寫的,并被基于Chrome的瀏覽器使用,如Chrome、Opera甚至Edge。基本上,這個(gè)引擎是一個(gè)將 JS 轉(zhuǎn)換成機(jī)器碼并在計(jì)算機(jī)的中央處理器(CPU)上執(zhí)行結(jié)果的程序。

編譯

當(dāng)瀏覽器加載 JS 文件時(shí),V8的解析器將其轉(zhuǎn)換為一個(gè)抽象語法樹(AST)。該樹用于生成字節(jié)碼的解釋器。字節(jié)碼是一種可以通過編譯成非優(yōu)化的機(jī)器碼來執(zhí)行的機(jī)器碼的抽象。V8在主線程中執(zhí)行它,而優(yōu)化編譯器TurboFan在另一個(gè)線程中進(jìn)行一些優(yōu)化并生成優(yōu)化的機(jī)器碼。

這個(gè)管道稱為即時(shí)(JIT)編譯。

JavaScript內(nèi)部原理:瀏覽器的內(nèi)幕

調(diào)用堆棧

JavaScript 是一種單線程編程語言,只有一個(gè)調(diào)用堆棧。它意味著我們的代碼是同步執(zhí)行的。每當(dāng)一個(gè)函數(shù)運(yùn)行時(shí),它將在任何其他代碼運(yùn)行之前完全運(yùn)行。

當(dāng)V8調(diào)用 JS 函數(shù)時(shí),它必須將運(yùn)行時(shí)數(shù)據(jù)存儲(chǔ)在某個(gè)地方。調(diào)用堆棧是內(nèi)存中由堆棧幀組成的位置。每個(gè)堆棧幀對(duì)應(yīng)于一個(gè)尚未被調(diào)用函數(shù)。堆棧結(jié)構(gòu)由以下組成:

  • 局部變量
  • argument 參數(shù)
  • 返回地址

如果我們執(zhí)行一個(gè)函數(shù),V8 會(huì)將幀推到棧頂。當(dāng)我們從一個(gè)函數(shù)返回時(shí),V8 會(huì)跳出幀。

JavaScript內(nèi)部原理:瀏覽器的內(nèi)幕

如上例所示,在每次函數(shù)調(diào)用時(shí)都會(huì)創(chuàng)建一個(gè)幀,并在每個(gè)return語句中將其刪除。

其他所有內(nèi)容都動(dòng)態(tài)地分配到一個(gè)稱為堆的大型非結(jié)構(gòu)化內(nèi)存塊中。

堆(Heap)

有時(shí)V8在編譯時(shí)不知道對(duì)象變量需要多少內(nèi)存。此類數(shù)據(jù)的所有內(nèi)存分配都發(fā)生在堆中。退出分配內(nèi)存的函數(shù)后,堆上的對(duì)象繼續(xù)存在。

V8有一個(gè)內(nèi)置的垃圾收集器(GC)。垃圾收集是內(nèi)存管理的一種形式。它就像一個(gè)收集器,試圖釋放不再使用的對(duì)象占用的內(nèi)存。換句話說,當(dāng)一個(gè)變量失去所有引用時(shí),GC將該內(nèi)存標(biāo)記為不可訪問并釋放它。

我們可以通過在Chrome開發(fā)工具中創(chuàng)建快照來研究堆。

JavaScript內(nèi)部原理:瀏覽器的內(nèi)幕

實(shí)例化的每個(gè) JS 對(duì)象都分組在其構(gòu)造函數(shù)類下。括號(hào)中的分組表示不能直接調(diào)用的原生構(gòu)造函數(shù)??梢钥吹接泻芏?編譯代碼)和(系統(tǒng))實(shí)例,但也有一些傳統(tǒng)的 JS 對(duì)象,如Math、String、Array等。

瀏覽器運(yùn)行時(shí)

V8可以根據(jù)標(biāo)準(zhǔn),同步地使用一個(gè)調(diào)用堆棧來執(zhí)行 JS 。但,我們需要渲染UI,需要處理用戶與UI的交互。此外,我們還需要在發(fā)出網(wǎng)絡(luò)請(qǐng)求時(shí)處理用戶交互,對(duì)此卻無能為力。當(dāng)所有代碼都是同步的時(shí)候,我們?nèi)绾螌?shí)現(xiàn)并發(fā)呢? 這還得感謝瀏覽器引擎。

瀏覽器引擎負(fù)責(zé)用 HTML 和 CSS 渲染頁面。在 Chrome 中它被稱為Blink。它是WebCore的一個(gè)分支,Blink 是一個(gè)布局、渲染和文檔對(duì)象模型(DOM)庫。Blink 是用 c++ 中實(shí)現(xiàn)的,它提供了DOM元素和事件、XMLHttpRequest、fetch、setTimeout、setInterval等 Web api,這些api可以通過 JS 訪問。

我們一起思考下面帶有setTimeout(onTimeout, 0)的示例:

JavaScript內(nèi)部原理:瀏覽器的內(nèi)幕

可以看到,瀏覽器首先將f1()和f2()函數(shù)推入堆棧,然后執(zhí)行onTimeout。那么上面的示例如何工作?

并發(fā)性

setTimeout函數(shù)執(zhí)行后,瀏覽器引擎立即將setTimeout的回調(diào)函數(shù)放入一個(gè)事件表中。它是一個(gè)數(shù)據(jù)結(jié)構(gòu),將注冊(cè)的回調(diào)映射到事件,在我們的例子中是onTimeout函數(shù)映射到timeout事件。

一旦計(jì)時(shí)器到時(shí),在本例中,我們將延遲設(shè)為0 ms,則立即觸發(fā)事件,并將onTimeout函數(shù)放入事件隊(duì)列(又名回調(diào)隊(duì)列,消息隊(duì)列或任務(wù)隊(duì)列)中。事件隊(duì)列是一種數(shù)據(jù)結(jié)構(gòu),由將來要處理的回調(diào)函數(shù)(任務(wù))組成。

最后且重要的是,事件循環(huán)(一個(gè)不斷運(yùn)行的循環(huán))檢查調(diào)用堆棧是否為空。如果是,則執(zhí)行從事件隊(duì)列中添加的第一個(gè)回調(diào),從而移動(dòng)到調(diào)用堆棧。

函數(shù)的處理將繼續(xù),直到調(diào)用堆棧再次為空。然后,事件循環(huán)將處理事件隊(duì)列中的下一個(gè)回調(diào)(如果有的話)。

JavaScript內(nèi)部原理:瀏覽器的內(nèi)幕

JavaScript內(nèi)部原理:瀏覽器的內(nèi)幕

注意onResolve1、onResolve2和onTimeout回調(diào)的執(zhí)行順序。

阻塞和非阻塞

簡單地說,所有 JS 代碼都被認(rèn)為是阻塞的。當(dāng) V8 忙于處理堆棧幀時(shí),瀏覽器被卡住了,應(yīng)用程序的 UI 被阻塞。用戶將無法單擊、導(dǎo)航或滾動(dòng)。直到 V8 完成它的工作,才會(huì)處理來自網(wǎng)絡(luò)請(qǐng)求的響應(yīng)。

想象一下,我們?nèi)绻跒g覽器中運(yùn)行的程序中解析圖像。

JavaScript內(nèi)部原理:瀏覽器的內(nèi)幕

JavaScript內(nèi)部原理:瀏覽器的內(nèi)幕

在上面的示例中,事件循環(huán)被阻止。它無法處理事件/作業(yè)隊(duì)列中的回調(diào),因?yàn)檎{(diào)用堆棧包含這一幀。

Web API 為我們提供了通過異步回調(diào)來編寫非阻塞代碼的可能性。當(dāng)調(diào)用像setTimeout或fetch這樣的函數(shù)時(shí),我們把所有的工作委托給c++原生代碼,它在一個(gè)單獨(dú)的線程中運(yùn)行。一旦操作完成,回調(diào)就被放入事件隊(duì)列。同時(shí),V8可以繼續(xù)執(zhí)行 JS 代碼。

使用這種并發(fā)模型,我們可以處理網(wǎng)絡(luò)請(qǐng)求、用戶與UI的交互等等,而不會(huì)阻塞 JS 執(zhí)行線程。

總結(jié)

對(duì)于希望能夠解決復(fù)雜任務(wù)的每個(gè)開發(fā)人員來說,理解 JS 環(huán)境由什么組成是至關(guān)重要的?,F(xiàn)在我們知道了異步JavaScript是如何工作的,調(diào)用堆棧、事件循環(huán)、事件隊(duì)列和作業(yè)隊(duì)列在其并發(fā)模型中的角色。

你可能已經(jīng)猜到的,在V8引擎和瀏覽器引擎后面還有很多工作要做。然而,我們大多數(shù)人只是需要對(duì)所有這些概念有一個(gè)基本的理解。

 

責(zé)任編輯:趙寧寧 來源: 今日頭條
相關(guān)推薦

2012-02-01 13:42:19

2017-01-05 09:07:25

JavaScript瀏覽器驅(qū)動(dòng)

2020-11-06 15:20:45

瀏覽器前端架構(gòu)

2013-05-23 16:01:56

瀏覽器

2013-06-14 13:56:29

瀏覽器渲染原理

2016-10-09 08:38:01

JavaScript瀏覽器事件

2019-01-03 13:09:58

瀏覽器緩存原理

2021-04-19 11:40:15

瀏覽器路徑

2010-09-15 09:12:03

JavaScript瀏覽器兼容

2010-04-05 21:57:14

Netscape瀏覽器

2022-08-30 09:01:11

瀏覽器渲染前端

2018-11-30 09:00:19

html5cssjavascript

2012-03-20 11:41:18

海豚瀏覽器

2012-03-20 11:31:58

移動(dòng)瀏覽器

2012-03-19 17:25:22

2021-12-09 07:54:19

瀏覽器引擎編譯

2012-03-20 11:07:08

2010-12-21 10:11:35

手機(jī)瀏覽器

2013-01-14 10:58:51

傲游云瀏覽器

2011-04-12 16:51:29

Javascript兼容性
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)