javasctipt 工做原理之調用棧

譯者注

翻譯一個對新手比較友好的 JavaScript 工做原理解析系列文章javascript

注意: 如下所有是概念,經驗豐富的老鳥能夠離場啦

正文從這裏開始前端

隨着 javascript 的流行,團隊們正在利用javascript來支持多個級別的技術棧,包括前端,後端,混合開發,嵌入式設備,以及更多java

這篇文章旨在成爲深刻挖掘JavaScript和實際上他是怎麼工做的系列文章中的第一篇:咱們經過知道javascript的模塊(Building blocks)和他們如何組合在一塊兒工做來寫更好的代碼和應用.咱們還會分享一些咱們構建sessionStarck(這是一款主打反饋功能的產品)時的經驗法則,一款輕量級的javascript應用爲了保持競爭力,必須時要健壯和高性能.node

據githut stats(這是一個統計網站,根據gihub的數據來進行語言統計)的數據來看 , JavaScript 是github 上 活躍庫最多的,和提交數最多的語言,這讓他不會落後於其餘類別.git

若是項目變得如此依賴於JavaScript,這就意味着,爲了開發驚豔的軟件(能夠理解爲程序),開發者不得不利用這個語言和生態系統(JavaScript生態)提供的一切,對內部的更深刻和更深刻的瞭解.github

事實證實,有很大一部分的開發者天天都在使用javascript,可是殊不知道javascript 在底層幹了啥(原文很長,其實就是這個意思,英文還真的是...)web

Overview

基本上每一個人都知道 v8 引擎這個概念了,大多數人知道javascript 是一個單線程語言 或者是那個使用回調隊列的語言.chrome

這篇文章,咱們將跑通哪些概念的細節和說明javascript是如何運行的,經過知道這些細節,你可以正確的使用提供的api書寫更好的,非阻塞的應用.編程

若是你是一個javascript新手,這篇文章能讓你知道爲何javascript對比與其餘語言,爲何如此神奇.後端

若是你是一個有經驗的javascript開發者,我也但願如此,這會給你一些關於javascript運行時是怎麼工做的閃亮的靈感(或者說新的看法).

javascript引擎

google v8 引擎是一個了流行的例子,nodejs 和 chrome 都是使用這個引擎,這裏是一個簡單的他看起來是什麼的圖

圖片描述

這個引擎看起來像是兩個組件.

  • memory Heap: 這是內存分配的位置
  • call Stack: 這是你的代碼執行時,堆棧幀(starck frame)的位置

運行時

在瀏覽器中有一些api已經被幾乎全部的javascript開發者使用了,例如 setTimeout 這些api,然而,他們不是又引擎提供的.

那麼,他們從哪裏來的呢?

其實這有點複雜.

圖片描述

看,咱們有引擎,可是其實咱們還有不少東西.咱們有那些瀏覽器提供的web apis,例如 DOM, AJAX, setTimeout等等.

並且,咱們還有流行的事件循環(even loop)和回調隊列(callback queue)

調用棧(回調隊列跟調用棧其實意思差很少,不過棧跟隊列是兩種不一樣的數據結構)

javascript是一個單線程的編程語言(repeat又repeat,都說幾回了),這意味着他有一個調用棧,所以,他一次只能作一件事情.

調用棧是一個記錄了咱們在程序中的位置的數據結構,若是咱們跳進一個function,咱們把這個函數放進棧的頂部(棧是一種先進後出的數據結構),若是咱們從function中return出來,咱們就從棧的頂部跳了出來,這就是棧能作的事情.

讓咱們來看一個例子:

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

當引擎執行這段代碼的時候,調用棧(call stack)是空的,當進入printSquare的時候,棧上添加了一個函數,在printSquare中咱們又進入了multiply中,此時棧的頂部又添加了一個函數,當咱們從multiply中return的時候,棧就把頂部的函數彈出,此時咱們就回到了printSquare裏,而後執行完printSquare後引擎自動return undefined 以結束這個函數的執行.

棧的每一次變化就想下面這樣:

圖片描述
棧中的每個條目(entry)叫坐堆棧幀(stack frames)上面有提到

這就是一個異常拋出時,棧追蹤是如何被構造的(how stack traces are being constructed)---這取決於異常發生的時候,回調棧的狀態.(忽然跑異常去了,實際上是想說明,異常就是經過調用棧實現的)

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

若是這段代碼在chrome執行,會產生下邊的棧追蹤(其實就是一個錯誤)

"棧壞了"(blowing the stack) --- 這發生在當你把棧放滿了的時候(下面還說了一大推,還貼了代碼,其實就是死遞歸)

當引擎執行死遞歸的時候,會不停的調用同一個方法.看起來像下面這樣.

圖片描述

然而,函數在調用棧上調用的數量超過了調用棧的實際大小,瀏覽器決定要採起行動了,因此他拋出了一個錯誤,看起來是這樣的

圖片描述

在單線程上運行代碼能夠很容易,由於你不用去處理多線程中的複雜場景,例如,死鎖.

可是,運行在單線程上也有他的限制,因爲javascript只有一個調用棧,如果程序執行得很慢怎麼辦?

併發和事件循環(even loop)

當你有函數調用在調用棧(call stack)裏爲了一個任務花費了大額的時間會發生什麼?例如,想象一下,你要在瀏覽器了作一個複雜的圖片轉性(transfromation).

你可能會問--爲何這是一個問題?問題是調用棧有函數在運行,瀏覽器就不能作其餘的事情,這就形成了阻塞,這意味這瀏覽器不能渲染,它不能運行任何的其餘代碼,它卡住了,若是你想你的app 的ui界面流暢,那麼這就是一個問題.

然而,這不是惟一的問題,一旦你的瀏覽器在調用棧開始了不少的任務,這可能會在很長的一段時間內失去響應.而不少的瀏覽器會拋出一個錯誤,而後問你是否要關閉網頁.

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

那麼,咱們要如何處理這種須要很長時間執行的代碼呢?嗯~,解決辦法就是異步回調

這會再第二篇文章中詳細說明.

下面開始買他們產品的廣告了,就不翻譯了.

原文第二篇我會盡快翻譯,儘可能不拖過久.

寫做新手,還望你們多多關注,多多點贊.

相關文章
相關標籤/搜索