摘要:調(diào)用棧是單線程編程語言,意味著它只有單一的調(diào)用棧。調(diào)用棧是一種數(shù)據(jù)結(jié)構(gòu),基本記錄了程序運行的位置。舉個例子,先來看如下所示的代碼當(dāng)引擎開始執(zhí)行這段代碼時,調(diào)用棧將是空的。這正是拋出異常時棧追蹤的構(gòu)造過程這基本上就是異常拋出時調(diào)用棧的狀態(tài)。
原文 How JavaScript works: an overview of the engine, the runtime, and the call stack
隨著 JavaScript 越來越流行,開發(fā)團隊也更多地利用其來支持技術(shù)棧的各方面,前端、后端、混合應(yīng)用、嵌入式設(shè)備等。
本文是旨在深入挖掘 JavaScript 其工作原理系列教程的首篇:我們認為通過了解 JavaScript 的構(gòu)建單元并熟悉它們是怎樣結(jié)合起來的,有助于你寫出更好的代碼和應(yīng)用。我們也會分享一些在構(gòu)建 SessionStack 應(yīng)用時用到的經(jīng)驗法則,為了維持其競爭力它是一個健壯、高性能的輕量級 JavaScript 應(yīng)用。
如GitHut stats所示,JavaScript 在活躍倉庫數(shù)和GitHub總推送數(shù)方面位于首位。在其他類別排名中落后的也不多。
(查看最新的統(tǒng)計)。
如果項目變得如此依賴 JavaScript ,這就意味著開發(fā)者必須更加深入地理解其內(nèi)部原理以充分利用語言和其生態(tài)提供的所有內(nèi)容,從而構(gòu)建更棒的軟件。
事實顯示,許多開發(fā)者每天都在使用 JavaScript 卻不知其底層發(fā)生了什么。
概述幾乎每個人都聽說過 V8 引擎的概念,大多數(shù)人也知道 JavaScript 是單線程的或者使用回調(diào)隊列。
在本文中,我們會詳細講解這些概念并闡述 JavaScript 是如何運行的。通過了解這些細節(jié),你就可以利用提供的 APIs 寫出更好的、無阻塞的應(yīng)用。
如果你對 JavaScript 相對陌生,這個博客可以幫助你理解為何與其他語言相比 JavaScript 如此怪異。
如果你是位經(jīng)驗豐富的 JavaScript 開發(fā)人員,也希望能提供給你一些每天都在使用的 JavaScript 運行時實際運作機制的新見解。
JavaScript引擎JS引擎的一個最流行的例子就是谷歌的 V8。 V8 引擎使用在例如 Chrome 瀏覽器和 Node.js 中。下圖是一個引擎組成部分的極簡視圖:
引擎由以下兩個主要部分組成:
內(nèi)存堆——這是內(nèi)存分配發(fā)生的地方
調(diào)用棧——這是代碼執(zhí)行時的堆棧幀所在位置
運行時幾乎所有 JavaScript 開發(fā)者都使用過瀏覽器提供的 APIs(如 setTimeout)。但是那些 APIs 并不由引擎提供。
那么,它們來自哪里?
其實實際情況更加復(fù)雜一些。
所以,除了引擎之外實際上還有更多東西。我們還有那些由瀏覽器提供 Web APIs,如 DOM、AJAX、setTimeout 等等。
并且,我們還有非常流行的事件循環(huán)和回調(diào)隊列。
調(diào)用棧JavaScript 是單線程編程語言,意味著它只有單一的調(diào)用棧。因此它一次只能做一件事。
調(diào)用棧是一種數(shù)據(jù)結(jié)構(gòu),基本記錄了程序運行的位置。如果進入一個函數(shù),就會把它推入到棧頂部。如果函數(shù)返回,就會將函數(shù)從棧頂部移除。這就是棧能做的事情。
舉個例子,先來看如下所示的代碼:
function multiply(x, y) { return x * y; } function printSquare(x) { var s = multiply(x, x); console.log(s); } printSquare(5);
當(dāng)引擎開始執(zhí)行這段代碼時,調(diào)用棧將是空的。之后的步驟如下圖所示:
調(diào)用棧的每一次進入稱為棧幀。
這正是拋出異常時棧追蹤的構(gòu)造過程——這基本上就是異常拋出時調(diào)用棧的狀態(tài)。看看下面的代碼:
function foo() { throw new Error("SessionStack will help you resolve crashes :)"); } function bar() { foo(); } function start() { bar(); } start();
在 Chrome 中執(zhí)行這段代碼時(假設(shè)這些代碼在foo.js文件中),會產(chǎn)生如下的棧追蹤記錄:
“棧溢出”——發(fā)生在達到最大調(diào)用棧的大小時。這非常容易發(fā)生,尤其是當(dāng)你使用了遞歸而未進行足夠的測試時,看看如下示例代碼:
function foo() { foo(); } foo();
當(dāng)引擎開始執(zhí)行這段代碼時,從調(diào)用 foo 函數(shù)開始。然而這個函數(shù)是遞歸的,它開始調(diào)用自己而沒有任何終止條件。所以在執(zhí)行的每一步中,相同的函數(shù)一次又一次添加到調(diào)用棧里。它看起來是這樣的:
但是,在某個時候,調(diào)用棧中函數(shù)的數(shù)量超過了它的實際大小,這時瀏覽器決定采取一些行動,拋出異常,它是這樣的:
在單線程上運行代碼十分簡單,因為不需要處理在多線程環(huán)境中遇到的復(fù)雜場景——例如,死鎖。
但單線程上的代碼運行也相當(dāng)受限。由于 JavaScript 只有單一的調(diào)用棧,當(dāng)運行非常慢時會發(fā)生什么呢?
并發(fā)和事件循環(huán)當(dāng)調(diào)用棧中存在大量耗時才能處理的函數(shù)時會發(fā)生什么?例如,假設(shè)你需要在瀏覽器中使用 JavaScript 執(zhí)行某些非常復(fù)雜的圖像轉(zhuǎn)換。
你也許會問——這有什么問題?問題在于當(dāng)調(diào)用棧中有函數(shù)等待執(zhí)行時,瀏覽器實際上無法做其他事情——它被阻塞了。這意味著瀏覽器無法繼續(xù)渲染,也不能運行其他代碼,它只是卡住了。如果你希望擁有流暢的用戶體驗,這就成了問題。
這并不是唯一的問題。一旦你的瀏覽器開始執(zhí)行棧里如此之多的任務(wù),它可能會在相當(dāng)長的時間里暫停響應(yīng)。大多數(shù)瀏覽器會采取報錯的行為,詢問你是否要關(guān)閉頁面。
這可不是最好的用戶體驗,不是嗎?
那么,我們要怎樣在既不阻塞 UI 又不導(dǎo)致瀏覽器無響應(yīng)的情況下執(zhí)行大量的代碼呢?解決方案是:異步回調(diào)。
這將在《JavaScript工作原理》教程的第二部分詳細解釋。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/103759.html
摘要:本文將會深入分析的引擎的內(nèi)部實現(xiàn)。該引擎使用在谷歌瀏覽器內(nèi)部。同其他現(xiàn)代引擎如或所做的一樣,通過實現(xiàn)即時編譯器在執(zhí)行時將代碼編譯成機器代碼。這可使正常執(zhí)行期間只發(fā)生相當(dāng)短的暫停。 原文 How JavaScript works: inside the V8 engine + 5 tips on how to write optimized code 幾周前我們開始了一個系列博文旨在深入...
摘要:本系列的第一篇文章著重提供一個關(guān)于引擎運行時和調(diào)用棧的概述。在硬件層面,計算機內(nèi)存由大量的觸發(fā)器組成。每個觸發(fā)器包含幾個晶體管能夠存儲一個比特譯注位。可以通過唯一標(biāo)識符來訪問單個觸發(fā)器,所以可以對它們進行讀寫操作。比特稱為個字節(jié)。 原文 How JavaScript works: memory management + how to handle 4 common memory lea...
摘要:本章會對語言引擎,運行時,調(diào)用棧做一個概述。調(diào)用棧只是一個單線程的編程語言,這意味著它只有一個調(diào)用棧。查看如下代碼當(dāng)引擎開始執(zhí)行這段代碼的時候,調(diào)用棧會被清空。之后,產(chǎn)生如下步驟調(diào)用棧中的每個入口被稱為堆棧結(jié)構(gòu)。 原文請查閱這里,本文采用知識共享署名 4.0 國際許可協(xié)議共享,BY Troland。 本系列持續(xù)更新中,Github 地址請查閱這里。 這是 JavaScript 工作原...
摘要:本章會對語言引擎,運行時,調(diào)用棧做一個概述。調(diào)用棧只是一個單線程的編程語言,這意味著它只有一個調(diào)用棧。查看如下代碼當(dāng)引擎開始執(zhí)行這段代碼的時候,調(diào)用棧會被清空。之后,產(chǎn)生如下步驟調(diào)用棧中的每個入口被稱為堆棧結(jié)構(gòu)。 原文請查閱這里,本文采用知識共享署名 4.0 國際許可協(xié)議共享,BY Troland。 本系列持續(xù)更新中,Github 地址請查閱這里。 這是 JavaScript 工作原...
摘要:調(diào)用棧是一種單線程編程語言,這意味著它只有一個調(diào)用堆棧。調(diào)用棧是一種數(shù)據(jù)結(jié)構(gòu),它記錄了我們在程序中的位置。而且這不是唯一的問題,一旦你的瀏覽器開始處理調(diào)用棧中的眾多任務(wù),它可能會停止響應(yīng)相當(dāng)長一段時間。 本文是旨在深入研究JavaScript及其實際工作原理的系列文章中的第一篇:我們認為通過了解JavaScript的構(gòu)建塊以及它們是如何工作的,將能夠編寫更好的代碼和應(yīng)用程序。我們還將分...
閱讀 2389·2019-08-30 15:56
閱讀 1048·2019-08-30 15:55
閱讀 3210·2019-08-30 15:44
閱讀 939·2019-08-30 10:53
閱讀 1894·2019-08-29 16:33
閱讀 2493·2019-08-29 16:13
閱讀 726·2019-08-29 12:41
閱讀 883·2019-08-26 13:56