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