隨着JavaScript愈來愈受歡迎,團隊正在利用這個技術棧在多個層次- 前端,後端,混合應用程序,嵌入式設備等等提供支持。javascript
這篇文章旨在成爲系列中第一個旨在深刻挖掘JavaScript及其實際工做的系列文章:咱們認爲,經過了解JavaScript的構建方式以及它們如何協同構建,您將可以編寫更好的代碼和 應用。前端
如GitHub統計所示,JavaScript在GitHub中的活躍庫數量和總推送數量位居前列。 在其餘類別中也不會落後於不少。java
若是項目愈來愈依賴JavaScript,這意味着開發人員必須利用語言和生態系統提供的全部內容來更深刻地瞭解內部內容,以便構建出使人驚豔的軟件。github
事實證實,有不少開發人員天天都在使用JavaScript,但不知道什麼會發生什麼。編程
幾乎全部人都已經據說過V8引擎的概念,大多數人都知道JavaScript是單線程的,或者是使用回調隊列。後端
在這篇文章中,咱們將詳細介紹全部這些概念,並解釋JavaScript如何運行。 經過了解這些細節,您將可以編寫更好的非阻塞應用程序,正確利用提供的API。瀏覽器
若是您接觸JavaScript不久,此博文將幫助您瞭解爲何JavaScript與其餘語言相比是如此「奇怪」。session
若是您是一位經驗豐富的JavaScript開發人員,但願可以爲您提供一些新的看法,瞭解您天天使用的JavaScript運行時間是否真的有效。數據結構
JavaScript引擎的一個流行示例是Google的V8引擎。 例如,V8引擎在Chrome和Node.js中使用。 這是一個很簡單的視圖:
引擎由兩個主要組成部分組成:
瀏覽器中已經有幾個JavaScript開發人員使用的API(例如「setTimeout」)。 然而,引擎不提供這些API。
那麼他們從哪裏來?
事實證實,現實有點複雜。
因此,咱們有引擎,但實際上還有更多。 咱們有一些稱爲Web API的東西,由瀏覽器提供,如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的文件中),則會產生如下堆棧跟蹤:
「Blowing the stack」 - 當您達到最大調用堆棧大小時,會發生這種狀況。 這可能會很容易發生,特別是若是您在不常常地對代碼進行測試的狀況下使用遞歸。 看看這個示例代碼:
function foo() { foo(); } foo();
當引擎開始執行這個代碼時,它首先調用函數「foo」。 然而,這個函數是遞歸的,而且開始調用自身而沒有任何終止條件。 因此在執行的每一個步驟中,相同的功能被一次又一次地添加到調用堆棧中。 看起來像這樣:
然而,在某些時候,調用堆棧中的函數調用次數超過了調用堆棧的實際大小,而且瀏覽器決定採起行動,經過拋出一個錯誤,看起來像這樣:
在單個線程上運行代碼可能很是容易,由於您沒必要處理在多線程環境中出現的複雜場景,例如死鎖。
可是在單線程上運行也是很是有限的。 因爲JavaScript有一個調用堆棧,當運行緩慢時會發生什麼?
當您在調用堆棧中進行函數調用須要大量時間才能處理時會發生什麼? 例如,假設您想在瀏覽器中使用JavaScript進行一些複雜的圖像轉換。
你可能會問 - 爲何這甚至是一個問題? 問題是,雖然調用堆棧具備執行的功能,但瀏覽器實際上不能作任何事情 - 它被阻止。 這意味着瀏覽器沒法渲染,它不能運行任何其餘代碼,它只是卡住了。 若是您想要在應用中使用流暢的UI,這會產生問題。
這不是惟一的問題。 一旦您的瀏覽器開始處理Call Stack中的這麼多任務,它可能會中止響應很長時間。 大多數瀏覽器經過提出錯誤來採起行動,詢問您是否要終止網頁。
如今,這不是最好的用戶體驗,是嗎?
那麼,如何在不阻塞UI並使瀏覽器無響應的狀況下執行繁重的代碼呢? 那麼解決方案是異步回調。
這將在「JavaScript如何實際工做」教程的第2部分中更詳細地解釋:「V8引擎內有關如何編寫優化代碼的5個提示」。
翻譯自How JavaScript works: an overview of the engine, the runtime, and the call stack
關注個人公衆號,更多優質文章定時推送