JavaScript 的異步和單線程

問題

Q:下面的代碼是否能滿足sleep效果?

var t = true;
setTimeout(function(){ t = false; }, 1000);
while(t){ }
alert('end');

一開始我認爲setTimeout是異步操作,一定會放在一個單線程裏工作,並不會受主線程影響;事實是settimeout函數並無法執行,瀏覽器因爲while死循環假死,也就是說setTimeout是沒有機會執行的。之後搜相關資料發現js引擎是單線程的。

爲什麼設計爲單線程?

JavaScript語言的一大特點就是單線程,也就是說,同一個時間只能做一件事。那麼,爲什麼JavaScript不能有多個線程呢?這樣能提高效率啊。
JavaScript的單線程,與它的用途有關。作爲瀏覽器腳本語言,JavaScript的主要用途是與用戶互動,以及操作DOM。這決定了它只能是單線程,否則會帶來很複雜的同步問題。比如,假定JavaScript同時有兩個線程,一個線程在某個DOM節點上添加內容,另一個線程刪除了這個節點,這時瀏覽器應該以哪個線程爲準?
所以,爲了避免複雜性,從一誕生,JavaScript就是單線程,這已經成了這門語言的核心特徵,將來也不會改變。
爲了利用多核CPU的計算能力,HTML5提出Web Worker標準,允許JavaScript腳本創建多個線程,但是子線程完全受主線程控制,且不得操作DOM。所以,這個新標準並沒有改變JavaScript單線程的本質。
摘自 http://www.ruanyifeng.com/blog/2014/10/event-loop.html

單線程如何異步,如何併發?

我們知道,在一段程序代碼中發起一個調用並等待直到調用返回結果再執行接下來的代碼,這個調用對於這段程序來說是同步的;而發起一個調用後不用等待調用結果而直接執行後面的代碼,這個調用對於這段程序來說就是異步的。

異步意味着在主邏輯中被異步調用的代碼和主邏輯繼續執行的代碼會同時執行,這其實是實現了併發。回想一下我們在 Java 或者其它多線程語言中是如何實現異步的,一般來說,要創建一個異步任務,我們通常會創建一個線程然後在線程中執行該任務,這個任務和創建它的線程就可以併發執行了。但 Javascript 單線程的特性顯然和這異步、併發是有衝突的,那麼爲什麼說 Javascript 支持異步,支持併發呢?

其實理解起來也很簡單,Javascript 本身並不是異步的,而 Javascript 程序是異步的。具體來說就是,Javascript 編寫的代碼自身運行於單線程中,當遇到 IO 調用,就把它丟給運行時環境處理,自身繼續執行後面的代碼,當 IO 調用有了結果,會將結果及回調放在一個隊列裏,Javascript 線程會在合適的時機將回調函數取出並執行。

Javascript 程序的異步由其運行時環境提供,通過event loop實現異步編程,並提供併發支持。

實現異步編程可以有很多種方式(編程模型),想了解更多可以先看看這篇文章。

摘自 http://cnodejs.org/topic/579e341885dba6b12ac58583

僞sleep效果

stackoverflow 有給出解決方案的:

function sleep (time) {
    return new Promise((resolve) => setTimeout(resolve, time));
}

// Usage!
sleep(1000).then(() => {
    // Do something after the sleep!
    alert('hello')
})

對於日常使用,使用settimeout一般都能滿足。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章