文章翻譯自How Javascript work系列的第一篇How JavaScript works: an overview of the engine, the runtime, and the call stackjavascript
Javascript語言愈來愈流行,不管我的仍是團隊能夠把它應用在前端、後端、混合app、嵌入式等愈來愈多的技術方向上。前端
本篇將是我關於Javascript是如何工做的系列中的第一篇文章,深度理解Javascript中building blocks*(保證文章的嚴謹,Javascript中的專有名詞我會保留翻譯)*和如何組織building blocks工做的原理將會有利於程序員寫出更加健壯的代碼。我也會在這個文章系列中分享一些在咱們構建SessionStack時,爲保證輕量級的Javascript應用更健壯、更高的性能表現所使用到的一些不被大衆熟知的特性。java
經過GitHut Stats的排名,咱們能夠看出Javascript在Github倉庫活躍度和提交代碼總量兩個維度上都是排在第一名,在其它衡量標準的維度上Javascript的表現也是可圈可點。 git
若是項目對Javascript的依賴強度很大,爲了構建一個穩定的程序每位開發者都必須瞭解Javascript的特性和Javascript的內部原理。程序員
但現實情況卻非如此,儘管大批的開發者中天天都在使用Javascript做爲平常基礎開發語言,對Javascript是如何工做的原理卻知之甚少。chrome
幾乎每位開發者都據說過V8引擎的概念,許多開發者知道Javascript是單線程或Javascript使用callback隊列。編程
在這篇文章中,我將詳細闡述這些概念以及Javascript是如何工做的。這些細節將有助你寫出更健壯、非阻塞的應用程序。後端
若是你是一位Javascript新手,這一系列文章將會讓你知道爲何Javascript相較其它開發語言是如此驚豔。瀏覽器
若是你是一位資深Javascript開發者,我多但願這一系列的文章可讓你對天天使用的Javascript Runtime有一些新的洞見。bash
Google’s V8是流行的Javascript引擎之一,它使用在Chrome瀏覽器和Node.js中。下面是V8引擎一個簡化的視圖:
V8引擎主要包含兩個部分:
有一些APIs被開發者在瀏覽器中常用到(如:「setTimeout」),然而這些APIs也許並非由Javascript引擎提供的。
它們來自於哪裏呢? 它們的來歷有些複雜。
諸如DOM、AJAX、setTimeout等其它是由瀏覽器提供的,咱們稱之爲WEB APIs。
接下來,咱們將談談很是流行的callback queue和event loop。
Javascript是一種單線程的編程語言,這致使它只有單一的Call Stack。所以在某一時刻,他只能作一件事。
Call Stack是一種數據結構,他主要是記錄Javascript整個執行過程。當Javascript的虛擬機執行一個函數,就會把這個函數推送到Call Stack中。當這個函數返回值或是執行完畢後,這個函數就會從Call Stack刪除。
讓咱們一塊兒看一個例子,注意下面的代碼:
function multiply(x, y) {
return x * y;
}
function printSquare(x) {
var s = multiply(x, x);
console.log(s);
}
printSquare(5);
複製代碼
當Javascript引擎在執行這段代碼的前一刻,Call Stack是空的。而後Call Stack將會按照下圖發生變化。
看下面的代碼,這段代碼模擬在Call Stack中出現異常後的全過程。
function foo() {
throw new Error('SessionStack will help you resolve crashes :)');
}
function bar() {
foo();
}
function start() {
bar();
}
start();
複製代碼
假設這段代碼在foo.js中,foo.js在chrome瀏覽器執行後將會出現下面的堆棧追蹤記錄。
**堆棧溢出:**Javascript引擎產生的堆棧超過Javascript運行環境所提供的最大數量。這種異常在代碼中存在遞歸但沒有設置遞歸結束的條件時,尤爲容易產生。 下面就是這種類型的代碼:
function foo() {
foo();
}
foo();
複製代碼
Javascript引擎執行這段代碼是從foo函數開始,在這個函數中不斷調用本身並無設置終止條件,從而產生無限循環。每一次執行foo,Call Stack都會添加一次函數。這就像下面顯示的那樣:
當Javascript引擎中的Call Stack的長度,超過Javascript執行環境中Call Stack的實際長度時,Javascript執行環境(Chrome瀏覽器或Node)就會拋出下面的異常。
在多線程環境中,要考慮諸如死鎖等複雜執行過程。單線程的環境中相比較要簡單不少,可是單線程一樣有它的限制。Javascript單線程的執行環境中,如何應對複雜的調用,單線程會不會限制程序的性能。
當在你的Call Stack中存在一個須要佔用至關大執行時間的函數時,將會發生什麼。例如在瀏覽器中經過Javascript傳輸一個比較大的image文件時,你會怎麼作?
你也許會問這怎麼也算是一個問題。當Call Stack有待執行的函數時,瀏覽器會阻塞在這裏,並不作其它的任務。這也意味着你不可能在app中呈現流暢複雜的UI。
問題不只僅如此,一旦Call Stack中等待執行的任務不少時,瀏覽器要在很長的時間內都不能迴應其它事件。許多瀏覽器這時都會拋出一個提示信息,徵求你是否要關閉頁面。
這樣必然將致使很是差的用戶體驗。咱們如何在複雜的環境下既不阻塞UI同時也不使瀏覽器長時間沒有迴應?好吧,這裏我就不賣關子了,可使用異步回調。 這將會是我在Javascript是如何工做的系列文章的第二篇《V8引擎的內核和5個寫出高質量代碼的技巧》