在Javascript單線程
該篇文章中有提到,大部份這種單線程但可以處理非同步
的語言都有共同的特性那就是事件驅動(Event Driven)
,它一般是由通過事件循環(Event Loop)
與事件隊列(Event Queue)
來實現。
事件驅動 ( Event Driven ) 與事件隊列( Event Queue )
先來說說事件驅動(Event Driven)
,這種類型的程式執行流程基本上是由使用者的動作例如點擊了頁面或按了ENTER
之類的事件來決定,而不像一些如批次程式設計(batch programming)
是由程式開發者來決定。
我們來看看下面這張Philip Roberts
在JSConf EU 2014講述Javascript event-loop時所出現的這圖。
首先左上角為V8 Javascript runtime
,其中裡面的Stack代表JS接下來要做的事情(嚴格來說要做的任務被分配到的記憶體空間)由上至下來執行。Philip Roberts在演講中也有提到因javascript單線程而所擁有的等式。
one thread == one call stack == on thing at time
其中Stack
裡面的工作有些是非同步事件,例如ajax或settimeout等,stack會將工作丟給WebApis該區塊進行(嚴格來說是v8中某個東西會丟),等到執行完後成,會發送個callback給callbackQueue,等到Stack完全清空時,會至callback queue
裡尋找看看有沒有callback
要執行。
Javascript程式碼單線程運行流程範例
我們將以下列這段簡單的程式碼來看Javascript的執行流程。
console.log("hi")
setTimeout(function cb(){
console.log("there");
},5000);
console.log("Mark Lin");
首先為第一張圖,在還沒執行程式程式碼時,所有的Stack
與Task Quenu
都是空的。
然後我們開始執行,首先載入這段JS,Stack
會產生main()
這個區塊,再執行到
console.log('hi')
時,也會在Stack
產生console.log('hi')
的區塊,並在Console印出hi
,最後console.log('hi')
工作完成,會從Stack中釋放出。
執行到setTimeoout
,Stack
會產生setTimeout
的區塊,並且會向api發送工作,然後繼續往下執行。
執行console.log("Mark Lin")
,最後工作剛成後,Stack
全部清空。
Stack
全部空間釋放完後,同時也發現剛剛對api的請求已完成,並且已將CallBack cb
放置Task Quenu
,並且由於Stack
已清空,它會自動去Task Quenu
尋找Task
,這時發現了Cb然後就執行consoel.log("there")
。