首頁 > web前端 > js教程 > 詳解JavaScript運行機制以及概念分析

詳解JavaScript運行機制以及概念分析

零到壹度
發布: 2018-04-09 14:53:31
原創
2112 人瀏覽過

對JavaScript有個很模糊的印象,它是單執行緒異步的。本文主要來說說JavaScript到底是怎麼運作的。但在這之前,讓我們先理一下這些概念(現學現賣)

基本概念

執行緒與行程

行程(Process)是系統資源分配與調度的單元。一個運作著的程式就對應了一個行程。一個進程包括了運行中的程式和程式所使用到的記憶體和系統資源。如果是單核心CPU的話,在同一時間內,有且只有一個行程在運作。但是,單核心CPU也能實現多任務同時運行,例如你邊聽網易雲音樂的每日推薦歌曲,邊在網易有道雲筆記上寫博文。這算開了兩個進程(多進程),那運行的機制就是一會兒播放一下歌,一會兒響應一下你的打字,但由於CPU切換的速度很快,你根本感覺不到,以至於你認為這兩個進程是在同時運行的。進程之間是資源隔離的。

那線程(Thread)是什麼?執行緒是進程下的執行者,一個行程至少會開啟一個執行緒(主執行緒),也可以開啟多個執行緒。例如網易雲音樂一邊播放音頻,一邊顯示歌詞。多進程的運行其實也就是透過進程中的執行緒來執行的。一個行程下的執行緒是共享資源的。當多個執行緒同時操作同一個資源的時候,就會出現資源爭搶的問題。這又是另外一個問題了。

並行與並行

並行(Parallelism)是指程式的運作狀態,在同一個時間內有幾件事情並行在處理。由於一個執行緒在同一時間只能處理一件事情,所以並行需要多個執行緒在同一時間執行多件事情。

而並發(Concurrency)是指程式的設計結構,在同一時間內多件事情能被交替地處理。重點是,在某個時間內只有一件事情在執行。例如單核心CPU能實現多任務運行的過程就是並發的。

同步與非同步

同步非同步是指程式的行為。同步(Synchronous)是程式發出呼叫的時候,一直等待直到回傳結果,沒有結果之前不會回傳。也就是說,同步是呼叫者主動等待呼叫過程。

非同步(Asynchronous)是發出呼叫之後,馬上回傳,但不會馬上回傳結果。呼叫者不必主動等待,當被呼叫者得到結果之後會主動通知呼叫者。

舉個例子,去奶茶店買飲料。同步就是,一個顧客說出需求(請求),然後一直等著服務生做好飲料,顧客拿到自己點的飲料之後才離開;然後下一個顧客繼續重複上述過程。非同步就是,顧客先排隊點單,點完之後拿著單子在一邊,等服務生做好之後會叫號,叫到你了你去拿就好。

所以執行緒跟同步異步沒有直接的關係,單執行緒也是可以實現異步的。至於實現的方式,以下會具體說到。

阻塞與非阻塞

阻塞與非阻塞是指等待狀態。阻塞(Blocking)是指呼叫在等待的過程中線程被「掛起」(CPU資源被分配到其他地方去了)。

非阻塞(Non-blocking)是指等待的過程CPU資源還在該執行緒中,執行緒還能做其他的事情。

以剛才排隊買飲料的例子,阻塞就是你在等待的時候什麼事情也做不了,而非阻塞是你在等待的時候可以管自己先做其他的事情。

所以,同步可以阻塞也可以非阻塞,非同步可以阻塞也可以非阻塞。

單執行緒的JS

大概理清楚上述概念之後呢,就知道單執行緒和非同步是沒有矛盾的。那JS是如何執行的呢? JS其實就是一門語言,說是單執行緒還是多執行緒得結合具體運行環境。 JS的運作通常是在瀏覽器中進行的,具體由JS引擎去解析和運行。下面我們來具體了解瀏覽器。

瀏覽器

目前最受歡迎的瀏覽器為:Chrome,IE,Safari,FireFox,Opera。瀏覽器的核心是多執行緒的。一個瀏覽器通常由以下幾個常駐的執行緒:

  • 渲染引擎執行緒:顧名思義,該執行緒負責頁面的渲染

  • ##JS引擎執行緒:負責JS的解析與執行

  • 定時觸發器執行緒:處理定時事件,例如setTimeout, setInterval

  • ##事件觸發執行緒:處理DOM事件
  • 非同步http請求執行緒:處理http請求
  • #需要注意的是,渲染執行緒和JS引擎執行緒是不能同時進行的。渲染線程在執行任務的時候,JS引擎線程會被掛起。因為JS可以操作DOM,若在渲染中JS處理了DOM,瀏覽器可能就不知所措了。

JS引擎

通常講到瀏覽器的時候,我們會說到兩個引擎:渲染引擎​​和JS引擎。渲染引擎就是如何渲染頁面,Chrome/Safari/Opera用的是Webkit引擎,IE用的是Trident引擎,FireFox用的是Gecko引擎。不同的引擎對同一個樣式的實作不一致,就導致了經常被人詬病的瀏覽器樣式相容性問題。這裡我們不做具體討論。

JS引擎可以說是JS虛擬機,負責JS程式碼的解析與執行。通常包括以下幾個步驟:

  • 詞法分析:將原始​​程式碼分解為有意義的分詞

  • ##語法分析:用語法分析器將分詞解析成語法樹

  • 程式碼產生:產生機器能執行的程式碼

  • 程式碼執行

不同瀏覽器的JS引擎也各不相同,Chrome用的是V8,FireFox用的是SpiderMonkey,Safari用的是JavaScriptCore,IE用的是Chakra。

回到JS是單線程這句話,本質上來說,是瀏覽器在運行時只開啟了一個JS引擎線程來解析和執行JS。那為什麼只有一個引擎呢?如果同時有兩個執行緒去操作DOM,瀏覽器是不是又要不知所措了? !

JS運行機制

說了這麼多之後,終於我們要說到JS的整個運行過程了。

同步執行

我們先看一下JS同步執行過程是怎麼做到的?這就牽涉到了一個很重要的概念──執行上下文。我的一篇譯文深入學習JavaScript閉包很詳細地說明了這個概念。

執行上下文記錄了程式碼運行時的環境,當前運行狀態下有且有一個執行上下文在運作。那執行上下文到底記錄了什麼呢?大概有詞法環境,變數環境等。舉個簡單的例子:

var x = 10;

function foo(){
    var y=20;
    function bar(){
        var z=15; 
    }
    bar();
}

foo();
登入後複製

程式碼運行,先進入全域上下文。然後執行

foo()的時候,就進入了foo上下文,當然此時全域上下文還在。當執行 bar()的時候,又進入了bar上下文。執行完畢bar(),回到foo上下文。執行完foo(),又回到全域上下文。所以,執行過程執行上下文會形成一個呼叫堆疊(Call stack),先進後出。

// 进栈
                                                          3 bar Context
    =>                      =>   2 foo Context     =>     2 foo Context
        1 global Context         1 global Context         1 global Context

// 出栈
3 bar Context
2 foo Context     =>   2 foo Context     =>                        =>
1 global Context       1 global Context         1 global Context
登入後複製

在JS執行過程中,有且僅有一個執行上下文在運作。因為JS是單線程的,一次只能做一件事。

以上的過程都是同步執行的。

非同步執行-事件循環

我們回顧JS中自帶了哪些原生的非同步事件:

  • setTimeout

  • setInterval

  • 事件監聽

  • #Ajax請求

  • etc. .

JS非同步的效果得益於瀏覽器的執行環境。實際上,瀏覽器又開了線程來處理這些BOM事件。範例:

function foo(){
    console.log(1);
}

function bar(){
    console.log(2);
}

foo();

setTimeout(function cb(){
    console.log(3);
});

bar();
登入後複製

依照上一節的分析,先進入全域上下文,執行至

foo(),進入了foo上下文環境;執行console.log(1),控制台輸出1;foo上下文環境出棧,運行至setTimeout,交給瀏覽器的定時處理線程;運行至bar() ,進入了bar上下文環境;執行console.log(2),控制台輸出2;foo上下文環境出棧;等到瀏覽器執行緒執行完setTimeout,返回cb()回呼函數至目前任務佇列;當發現執行堆疊為空時,瀏覽器的JS引擎會執行一次循環,將事件佇列的隊首出隊至JS執行堆疊中;執行cb(),進入cb上下文環境;執行console.log(3),控制台輸出3;事件佇列為空,全域上下文出棧。

以上就是JS引擎的事件循環機制,是實現非同步的一種機制。主要涉及到

瀏覽器執行緒任務佇列以及JS引擎。所以,我們可以看出,JS的非同步請求,借助了而它所在的運行環境瀏覽器來處理並且傳回結果。而且,這也解釋了為什麼那些回呼函數的this指向window,因為這些非同步的程式碼都是在全域上下文環境下執行的。

後話:不知道自己理解對了沒有,也不知道說得清楚不清楚。不當之處,歡迎指出。

參考資料:

  • JavaScript:徹底理解同步、非同步與事件循環(Event Loop)

  • 還在疑惑並發和並行?

  • IMWeb社群 瀏覽器進程?線程?傻傻分不清楚!

  • Javascript是單一執行緒的深入分析

  • JavaScript單執行緒與瀏覽器事件循環簡述

  • AlloyTeam 【轉向Javascript系列】從setTimeout說事件循環模型

  • 小鬍子JavaScript異步程式設計原理

  • ##阮一峰JavaScript 運行機制詳解:再談Event Loop
  • 【樸靈註解】JavaScript 運作機制詳解:再談Event Loop
  • Philip Roberts: Help, I'm stuck in an event-loop.

  • Philip Roberts: What the heck is the event loop anyway?

  • jquery中Ajax的非同步與同步

#

以上是詳解JavaScript運行機制以及概念分析的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板