JavaScript工做機制:第1部分

JavaScript工做機制:第1部分

本文轉載自:衆成翻譯
譯者:網絡埋伏紀事
連接:http://www.zcfy.cc/article/3965
原文:https://blog.sessionstack.com/how-does-javascript-actually-work-part-1-b0bacc073cfjavascript

隨着JavaScript愈來愈受歡迎,開發團隊正在將其用在技術棧的各個方面,包括 - 前端、後端、混合應用、嵌入式設備等等。前端

GitHut統計所示,JavaScript在GitHub中的活動存儲庫和總推送方面位於前列,在其餘方面也不差。java

查看最新的GitHub語言統計信息)。git

若是項目愈來愈依賴於JavaScript,這意味着開發人員必須更深刻地瞭解內部機制,才能利用語言和生態系統提供的全部技術,構建出驚豔的軟件。github

事實證實,雖然有不少開發人員天天都在使用JavaScript,但並不知道它的工做機制。編程

概述

幾乎全部人都已經據說過V8引擎的概念,大多數人都知道JavaScript是單線程的,或者是使用回調隊列。後端

在這篇文章中,咱們將詳細介紹全部這些概念,並解釋JavaScript的工做機制。經過了解這些細節,您將可以正確利用提供的API,編寫更好的非阻塞應用程序。瀏覽器

若是您是一個JavaScript新手,此博文將幫助您瞭解爲何JavaScript與其餘語言相比是如此「怪異」。微信

而若是您是一位經驗豐富的JavaScript開發人員,但願可以提供與您天天使用的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的文件中),則會產生如下棧跟蹤信息:

爆棧」 - 當達到最大調用棧大小時,就會發生這種狀況。而且這很是容易發生,特別是若是使用遞歸而不充分測試代碼時。請看以下示例代碼:

function foo() {
    foo();
}

foo();

當引擎開始執行這段代碼時,它首先調用函數「foo」。不過,這個函數是遞歸的,而且開始調用自身而沒有任何終止條件。因此在執行的每一個步驟中,相同的函數都被一次又一次地添加到調用棧中。看起來像這樣:

然而,在某些時候,若是調用棧中的函數調用量超過了調用棧的實際大小,瀏覽器就會決定採起行動,拋出一個錯誤,看起來像這樣:

在單個線程上運行代碼可能很容易,由於您沒必要處理在多線程環境中出現的複雜場景,例如死鎖。

但在單線程上運行也有很大限制。因爲JavaScript有一個調用棧,當事情緩慢時會發生什麼

併發和事件循環

當在調用棧中有函數調用須要大量時間才能處理完時,會發生什麼?例如,假設想在瀏覽器中使用JavaScript進行一些複雜的圖像轉換。

你可能會問 - 這怎麼就成了一個問題呢?緣由是,在調用堆有函數要執行的同時,瀏覽器實際上不能作任何事情 - 它被阻塞了。這意味着瀏覽器沒法渲染,它不能運行任何其餘代碼,它只是卡住了。若是想在應用中有流暢的UI,這會出問題。

而這不是惟一的問題。一旦瀏覽器開始處理調用棧中的許多任務,它可能會中止響應很長時間。大多數瀏覽器經過引起一個錯誤來採起行動,詢問您是否要終止網頁。

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

那麼,如何執行繁重的代碼,而不阻塞UI而且不會使瀏覽器無響應呢?好吧,解決方案是異步回調

我將在教程的第2部分中詳細介紹。敬請關注 :)


歡迎關注個人公衆號,關注前端文章:

justjavac微信公衆號

相關文章
相關標籤/搜索