JavaScript是如何工作的:引擎,運作時和調用堆棧的概述!
摘要: 了解JS執行原理。
- 原文:
- 作者: 前端小智
經授權轉載,版權歸原作者所有。
本文是旨在深入研究JavaScript及其實際工作原理的系列文章中的第一篇:我們認為通過了解JavaScript的建構塊以及它們是如何工作的,将能夠編寫更好的代碼和應用程式。我們還将分享建構
SeStHealsStad時使用的一些經驗法則,這是一個輕量級的 JavaScript 應用程式,必須保持健壯和高性能以保持競争力。
如
GitHut 統計資料所示,在GitHub中的活動存儲庫和總推送方面,JavaScript處于頂部。它也不落後于其他類别。

如果項目越來越依賴于 JavaScript,這意味着開發人員必須利用語言和生态系統提供的所有内容,對内部進行更深入的了解,以便建構出色的軟體。
事實證明,有很多開發人員每天都在使用JavaScript,但卻不知道背後發生了什麼。
概述
幾乎每個人都已經聽說過 V8 引擎,大多數人都知道 JavaScript 是單線程的,或者它使用的是回調隊列。
在本文中,我們将詳細介紹這些概念,并解釋 JavaScrip 實際如何運作。通過了解這些細節,你将能夠适當地利用所提供的 API 來編寫更好的、非阻塞的應用程式。
如果您對JavaScript還比較陌生,那麼本文将幫助您了解為什麼JavaScript與其他語言相比如此“怪異”。
如果你是一個有經驗的JavaScript開發人員,希望它能讓您對每天使用的JavaScript運作時的實際工作方式有一些新的見解。
JavaScript引擎
JavaScript引擎的一個流行示例是Google的V8引擎。例如,在Chrome和Node.js中使用V8引擎,下面是一個非常簡化的視圖:
V8引擎由兩個主要部件組成:
- emory Heap(記憶體堆) — 記憶體配置設定位址的地方
- Call Stack(調用堆棧) — 代碼執行的地方
Runtime(運作時)
有些浏覽器的 API 經常被使用到(比如說:setTimeout),但是,這些 API 卻不是引擎提供的。那麼,他們是從哪兒來的呢?事實上這裡面實際情況有點複雜。
是以說我們還有很多引擎之外的 API,我們把這些稱為浏覽器提供 API 稱為 Web API,比如說 DOM、AJAX、setTimeout等等。
然後我們還擁有如此流行的事件循環和回調隊列。
代碼部署後可能存在的BUG沒法實時知道,事後為了解決這些BUG,花了大量的時間進行log 調試,這邊順便給大家推薦一個好用的BUG監控工具
。
調用棧
JavaScript是一種單線程程式設計語言,這意味着它隻有一個調用堆棧。是以,它一次隻能做一件事。
調用棧是一種資料結構,它記錄了我們在程式中的位置。如果我們運作到一個函數,它就會将其放置到棧頂,當從這個函數傳回的時候,就會将這個函數從棧頂彈出,這就是調用棧做的事情。
來個栗子:
當程式開始執行的時候,調用棧是空的,然後,步驟如下:
每一個進入調用棧的都稱為調用幀。
這能清楚的知道當異常發生的時候堆棧追蹤是怎麼被構造的,堆棧的狀态是如何的,讓我們看一下下面的代碼:
如果這發生在 Chrome 裡(假設這段代碼實在一個名為 foo.js 的檔案中),那麼将會生成以下的堆棧追蹤:
"堆棧溢出",當你達到調用棧最大的大小的時候就會發生這種情況,而且這相當容易發生,特别是在你寫遞歸的時候卻沒有全方位的測試它。我們來看看下面的代碼:
當引擎開始執行這段代碼時,它首先調用函數“foo”。然而,這個函數是遞歸的,并且在沒有任何終止條件的情況下開始調用自己。是以,在執行的每一步中,相同的函數都會被一次又一次地添加到調用堆棧中,如下所示:
然而,在某些時候,調用堆棧中的函數調用數量超過了調用堆棧的實際大小,浏覽器決定采取行動,抛出一個錯誤,它可能是這樣的:
在單個線程上運作代碼很容易,因為你不必處理在多線程環境中出現的複雜場景——例如死鎖。
但是在一個線程上運作也非常有限制,由于 JavaScript 隻有一個調用堆棧,當某段代碼運作變慢時會發生什麼?
并發與事件循環
當調用堆棧中的函數調用需要花費大量時間來處理時會發生什麼情況? 例如,假設你希望在浏覽器中使用JavaScript進行一些複雜的圖像轉換。
你可能會問-為什麼這是一個問題?問題是,當調用堆棧有函數要執行時,浏覽器實際上不能做任何其他事情——它被阻塞了,這意味着浏覽器不能呈現,它不能運作任何其他代碼,它隻是卡住了,如果你想在應用中使用流暢的頁面效果,這就會産生問題。
而且這不是唯一的問題,一旦你的浏覽器開始處理調用棧中的衆多任務,它可能會停止響應相當長一段時間。大多數浏覽器都會這麼做,報一個錯誤,詢問你是否想終止 web 頁面。
這并不是最好的使用者體驗,不是嗎?
那麼,我們怎樣才能在不阻塞UI和不使浏覽器失去響應的情況下執行大量代碼呢?解決方案是異步回調。
這個在下一篇說明,我盡快把原作者的内容整理好!
How JavaScript works: an overview of the engine, the runtime, and the call stack關于Fundebug
專注于JavaScript、微信小程式、微信小遊戲、支付寶小程式、React Native、Node.js和Java線上應用實時BUG監控。 自從2016年雙十一正式上線,Fundebug累計處理了10億+錯誤事件,付費客戶有Google、360、金山軟體、百姓網等衆多品牌企業。歡迎大家
免費試用!