2014-01-29 20 views
6

我一直在閱讀John Resig的「JavaScript忍者的祕密」,它解釋說JavaScript是單線程的。不過,我試着測試此,我不知道該怎麼從這裏帶走:瞭解JavaScript的單線程本質

// executing this in browser 
(function() { 
    // throw something into event queue 
    setTimeout(function() { 
     alert("This will be called back after 1 second."); 
    }, 1000); 

    // arbitrary loop to take up some time 
    for (var i = 0; i < 10000; i += 1) { 
     console.log(i); 
    } 
})(); 

也許我不理解什麼是單線程的方式,但我認爲setTimeout的回調不會直到所有的外部匿名函數完成。但是,在瀏覽器中運行這個函數會顯示回調函數被調用,而我仍然被輸出到控制檯上。對我來說,這似乎有2線程與匿名函數的invokation佔用1線程,然後回調使用第二線程。

有人可以幫我解開困惑嗎?

+0

'console.log'是異步的,至少跨IE,Firefox,Chrome。更多:http://stackoverflow.com/questions/4057440/is-chromes-javascript-console-lazy-about-evaluating-arrays。異步不承擔多線程。 – Noseratio

回答

11

console.log()是在某些瀏覽器(如Chrome)一個奇怪的功能和不同步現象本身,所以你不能真正使用它來衡量單一threadedness。您可能看到的是,JS引擎執行所有console.log()語句,然後運行setTimeout()以顯示警報,並行(在其他一些不是javascript的過程中)所有數據都顯示在控制檯中。

Javascript確實是單線程的。在你的例子中,setTimeout()回調將不會執行,直到你的for循環完成。

您可以像這樣更好地說明它:

(function() { 
    // throw something into event queue 
    setTimeout(function() { 
     alert("This will be called back after 1 second."); 
    }, 1000); 

    function now() { 
     return new Date().getTime(); 
    } 
    var start = now(); 
    // loop for 1.2 seconds 
    while (now() - start < 1200) {} 
    alert("Looping done"); 
})(); 

工作的jsfiddle演示:http://jsfiddle.net/jfriend00/3sBTb/

+0

謝謝@ jfriend00!我沒有意識到console.log會很奇怪。您的代碼突出顯示了我期待看到的行爲! – wmock

3

John Resig covered this well.彙總:

「JavaScript可以永遠只執行一條代碼在時間(由於其 單線程性質)...在執行異步事件發生時(如 鼠標點擊,一個定時器觸發或一個XMLHttpRequest完成),它會被排隊等待稍後執行....在 的初始塊之後,JavaScript立即執行瀏覽器詢問 問題:什麼等待執行?然後瀏覽器選擇一個 並立即執行。[休息]將等到下一個 可能的時間,以執行。「

4

這是一個有點棘手概念的理解。投入事件聽衆等事情也會讓圖片更加混亂。

一個簡單的方法來思考它就好像你有一個傳送帶。你有正常的功能調用均勻間隔,有空間。

事情是異步的東西(超時,觸發事件等)填補這些地方。在這些正常呼叫之間沒有無限的空間,所以它適合它從這個隊列中可以得到的東西,多一點正常的同步功能,用異步方式填充更多空間等等。

影響似乎有點多線程(事實上,你可以通過異步調用導致競爭條件)。在許多情況下,這種區別並不重要。但是,記住這一點很重要。但是,當你嘗試調試東西時,尤其是在使用像Chrome的console.log這樣的工具時,它可能看起來像事物混亂,因爲console.log本身是異步的(如果它是同步的,它會將你的腳本凍結在一個長函數)。

你可以看到這個自己,如果你的輸出是這樣的:

var input = document.createElement('input'); 
input.setAttribute('value', 0); 

function inc() { 
    input.setAttribute('value', parseInt(input.getAttribute('value'))+1); 
    console.log(input); 

    if (parseInt(input.getAttribute('value')) < 100) { 
     setTimeout(inc, 10); 
    } 
} 

inc(); 

的jsfiddle:http://jsfiddle.net/c2PnP/

這是什麼腳本它創建了一個輸入元素,然後每隔10毫秒,它增加的價值輸入,然後輸出輸入元素。它重複100次(直到值= 100)。

如果你看看你的控制檯,你會注意到一些值將被複制,它不會是一個平穩的進展。例如,在我剛剛完成的一次運行中,我看到5個輸入的值爲「100」,缺少數字的差距。這是因爲console.log是異步運行的,只有在出現差距時纔會輸出。 (注意:如果您的計算機速度超快,您可能需要將時間縮短到更小的值,例如1,並且/或者將迭代次數增加到更大的值)。

+0

謝謝@samanime!傳送帶的類比真的幫助我更好地理解這一點! – wmock