譯—JavaScript是如何工做的(1):js引擎、運行時和調用棧的概述

原做者:blog.sessionstack.com/@zlatkovjavascript

隨着JS變得愈來愈流行,開發團隊們在多個級別的堆棧中都借力於js的支持- 前端,後臺,混合式應用開發,嵌入式設備等等。前端

這篇博文旨是咱們深刻挖掘JavaScript和其工做原理的系列文章的第一篇:咱們認爲經過了解JavaScript的構建塊和他們是如何共同發揮做用的,你能寫出更好的代碼和應用。咱們也會分享咱們在構建的一個輕量級的但必須具備強大和高性能的特色才能保持競爭力的JavaScript應用SessionStack時的一些經驗法則。java

正如GitHut Stats上的數據所示,JavaScript在github上的包活躍度和推送量居於領先地位。它也沒有落後於其餘類別的庫。node


查看github上最新的統計信息git

若是項目依賴JavaScript愈來愈多,則意味着開發者不得不用對其內部原理愈來愈深的理解來利用好語言和其生態系統所提供的一切以構建使人驚奇的軟件。github

事實證實,雖然有大量的開發者天天都會使用JavaScript,可是他們並不知道引擎蓋下發生了什麼。編程

概述 

幾乎人人都已經據說過V8引擎這個概念,大多數人也知道JavaScript是單線程或使用回調隊列。api

在本文中,咱們將會詳細地瞭解這些概念和解釋JavaScript其實是怎樣運行的。知道了這些細節後,你講可以寫出更好的、正確使用了提供的api的非阻塞的應用。瀏覽器

若是你對JavaScript這麼語言還比較陌生,那麼本文能夠幫助你理解爲甚JavaScript和其餘語言相比這麼「神奇」。bash

若是你已是一名富有經驗的JavaScript開發者,那咱們但願本文能在你天天都在使用的JavaScript運行時到底如何工做的問題上提供一些新的看法。

JavaScript 引擎

JavaScript引擎的一個流行實例是谷歌的V8引擎,V8引擎運用在谷歌瀏覽器和node.js內部。這裏有一個簡化的視圖:



引擎由主要由兩部分組成:

* 內存堆—這裏是內存分配發生的地方。

* 調用堆棧—這是當你的代碼執行時堆棧幀的位置

運行時

瀏覽器中有許多api幾乎每一個JavaScript開發者都使用過(好比「setTimeout」),然而,這些api並非引擎提供的。

那麼,他們是哪兒來的呢?

事實上,狀況有些複雜。


因此,咱們不只有引擎,還有更多東西。咱們有瀏覽器提供的Web APIs,好比,DOM, AJAX, setTimeout 等等。

此外,還有如此受歡迎的事件循環和回調隊列。

調用堆棧(The Call Stack)

JavaScript是一門單線程的編程語言,這意味着它只有一個堆棧(Call Stack),一次只能作一件事情。

堆棧是一種用來記錄代碼在程序中的位置的數據結構,當咱們運行到一個函數調用時,咱們把它放在堆棧的頂部,當函數運行完之後,咱們把它從堆棧的頂部移除(出棧)。這就是堆棧所能作的所有了。

讓咱們來看個例子,看看下面的代碼:


當引擎開始執行代碼的時候,堆棧裏面是空的。而後,會按下面這幾個步驟運行:


每一次進棧被稱爲一個棧幀(Stack Frame)。

這正是拋出異常時堆棧跟蹤的構造方式 — 它基本上是異常發生時調用堆棧的狀態。看看下面的代碼:


若是在谷歌瀏覽器中執行(假如是在一個叫foo.js的文件裏),將會發生如下的堆棧跟蹤:


「堆棧溢出(Blowing the stack)」—當達到堆棧調用最大容量時會發生這種狀況。要發生這種狀況也很簡單,尤爲是當你使用遞歸而沒有普遍地測試你的代碼的時候。看看下面的例子:

function foo(){
    foo()
};

foo();
複製代碼


當引擎開始執行這段代碼的時候,它開始調用‘foo’函數,然而‘foo’是一個遞歸它以調用它自己開始,而且沒有任何終止條件。因此,執行的每一步,這個函數會一遍又一遍地進棧。看起來就像這樣:


但到了必定程度,函數調用的數量超出了堆棧自己的容量,瀏覽器就會採起行動,拋出一個錯誤。相似這樣:


                    

在單線程中運行代碼會很是簡單,由於你不用處理一些發生在多線程環境裏的複雜場景。好比:死鎖(deadlocks)

可是在單線程中運行也有不少限制,因爲JavaScript只有一個Call Stack,那麼當事情變慢時會發生什麼?

併發和事件循環

若是在調用堆棧中有函數調用須要花費大量時間才能處理,會發生什麼?好比,想象一下你想用JavaScript在瀏覽器上作一些複雜的圖片轉換。

你或許會問—爲何這是一個問題?問題就是當堆棧裏有函數須要執行的時候,瀏覽器實際上任何其餘事都作不了—它被阻塞了。這就意味着瀏覽器不能渲染,不能執行任何其餘代碼,只能卡住了。若是你想要在你的應用中有流暢的UI,這就是個問題了。

這還不只僅是惟一的問題。一旦瀏覽器要在堆棧中處理不少任務的時候,可能會很長一段時間沒有響應。這時候大多數瀏覽器都會拋出錯誤,詢問你是否要終止該網頁。

                  

如今,這不是最好的用戶體驗,對嗎?

因此,咱們如何既能執行繁重的代碼同時也不會阻塞UI渲染或致使瀏覽器不響應呢?well,解決辦法就是異步回調。

這在「JavaScript如何工做」的第二部分教程「V8引擎內部+關於如何編寫優化代碼的5個技巧」(個人譯文)中有更詳細的解釋。

同時,若是你很難再現和理解你的JavaScript應用中出現的問題,你能夠看看SessionStack.

SessionStack記錄了你的應用中發生的任何事情:全部DOM更改,用戶交互,JavaScript異常,堆棧跟蹤,失敗的網絡請求和調試消息。

使用SessionStack,你能夠將網絡應用中的問題做爲視頻重播,並查看用戶發生的全部事情。

這兒有一個免費的方案,不須要任何的通行證。Get Start Now

相關文章
相關標籤/搜索