How JavaScript works - 1 (譯) js 如何工做

原文連接:an overview of the engine, the runtime, and the call stack

Foreword - 前言

隨着js愈來愈流行,團隊利用其在更多領域的堆棧,前端,後端,混合app,嵌入設備等。 這篇文章旨在深刻了解js以及它的工做原理。咱們都知道只有瞭解更多的js基礎才能夠寫出更好的代碼和app。javascript

Overview - 概覽

幾乎全部人都聽過V8引擎的概念,也知道js是一個單線程活使用回調隊列。 在這篇文章中咱們會詳細講解這些概念和解釋js工做原理。知道這些你能夠利用js提供的api,寫出更好的代碼,更流暢的app應用。 若是你剛接觸js,這篇博文會幫助你理解js和其餘語言相比下的不同凡響。 若是你是一個經驗豐富的js開發者,在你天天的工做的時候,在js如何運行上給你一些新的體驗。前端

The JavaScript Engine - js引擎

谷歌v8引擎是一個js引擎的典型案例。Chrome和node都是用了v8引擎。下面是一個簡單的例圖: java

圖片

v8引擎由兩部分組成:

  • Memory Heap - 內存堆:內存分配
  • Call Stack - 調用棧:調用棧框架代碼執行

The Runtime - 運行

瀏覽器提供的api幾乎被全部js開發者使用(eg:'setTimerout')。然而這些api並非v8引擎提供的。 所以他們來自哪裏呢? 事實證實現實是有一點複雜的。node

圖片

所以,咱們擁有引擎,但實際上還有更多的東西。有瀏覽器提供的web api,例如 dom,ajax,setTimeout等等。 並且,咱們還有超級流行的 event loop 和 回調隊列。web

The Call Stack - 調用棧

js是一個單線程的程序語言,意味着他只有一個調用棧。因此一次只能夠作一件事情。 The Call Stack is a data structure which records basically where in the program we are. 若是進入一個函數,咱們把它放入調用棧的頂端。若是我從一個函數返回,咱們把它從調用棧頂端移除,這就是調用棧作的全部事。 看下面demo:ajax

function multiply(x, y) {
        return x * y;
    }
    function printSquare(x) {
        var s = multiply(x, x);
        console.log(s);
    }
    printSquare(5);
複製代碼

當引擎開始執行代碼,調用棧是空的。而後,接下來的步驟如圖: 後端

圖片

調用棧中的每個表被稱爲一個 棧框架(Stack Frame) 當異常被拋出的時候,能夠清楚的知道堆棧追蹤是如何被構成的。異常發生時堆棧的狀態。看一下下面的代碼:api

function foo() {
        throw new Error('SessionStack will help you resolve crashes :)');
    }
    function bar() {
        foo();
    }
    function start() {
        bar();
    }
    start();
複製代碼

若是這發生在 Chrome 裏(假設這段代碼實在一個名爲 foo.js 的文件中),那麼將會生成如下的堆棧追蹤 瀏覽器

圖片

堆棧溢出(Blowing the stack) - 當你達到調用棧最大的大小的時候就會發生。並且很容易出現,特別是當你在沒有徹底的測試你的代碼的狀況下使用回調。看下面的簡單的代碼:session

function(){
        foo();
    }
    foo();
複製代碼

當引擎開始解析這段代碼的時候,就會開始調用foo函數,這個函數是一段從本身開始沒有任何終止條件的遞歸函數。所以在每一步的執行中,一樣的函數被一遍一遍放在調用棧中,這看起來就像這樣:

圖片
而後在某一時刻,當函數調用棧的數量超過實際調用棧的大小的時候,瀏覽器會經過拋出異常來採起行動。看起來就像這樣:
圖片
在單線程中很容易運行代碼由於你不用去處理多線程環境下的複雜場景-例如:死鎖。 可是在單線程中運行很容易被限制。由於js只有一個單線程,當運行變慢時發生了什麼?

Concurrency & the event loop - 併發&事件循環

當你有函數調用堆棧須要花費大量時間處理的時候,發生了什麼?例如,你想要在瀏覽器中使用js去作一些複雜的圖片處理的時候。 你可能會問-這怎麼是一個問題?問題是當調用棧有函數要執行。瀏覽器實際上不能夠作別的事情--它被鎖住了。這意味着瀏覽器不能夠被渲染,也不能夠執行其餘的代碼,它僅僅是卡住了。並且這會對於你想要完美的ui app中形成問題。 並且不單單是這一個問題。一旦你的瀏覽器在調用棧中開始執行這麼多任務,他可能會在很長時間內中止響應。絕大多數瀏覽器會採起提出一個錯誤,詢問你是否須要關閉web頁面。 如今,這難道不是一個很糟糕的用戶體驗? 因此,咱們在執行大量代碼的時候如何不會阻塞ui和瀏覽器流暢?就決方案就是 異步回調(asynchronous callbacks)。

會在第二章中有更詳細的解釋:Inside the V8 engine + 5 tips on how to write optimized code

相關文章
相關標籤/搜索