1. 程式人生 > >JS實現停留幾秒sleep,Js中for迴圈的阻塞機制,setTimeout延遲執行

JS實現停留幾秒sleep,Js中for迴圈的阻塞機制,setTimeout延遲執行

//第一種,使用while迴圈
function sleep(delay) {
    var start = (new Date()).getTime();
    while((new Date()).getTime() - start < delay) {
        continue;
    }
}
//或者使用for迴圈
function sleep(delay) {
    for(var t = Date.now(); Date.now() - t <= d;);
}

這種實現方式是利用一個偽死迴圈阻塞主執行緒。因為JS是單執行緒的。所以通過這種方式可以實現真正意義上的sleep()。

 

Js阻塞機制,跟Js引擎的單執行緒處理方式有關,每個window一個JS執行緒。所謂單執行緒,在某個特定的時刻只有特定的程式碼能夠被執行,並阻塞其它的程式碼。

      由於瀏覽器是事件驅動的(Event driven),因此瀏覽器中很多行為是非同步(Asynchronized)的,很容易有事件被同時或者連續觸發。當非同步事件發生時,會建立事件並放入執 行佇列中,等待當前程式碼執行完成之後再執行這些程式碼,如滑鼠點選事件發生、定時器觸發事件發生、XMLHttpRequest完成回撥這些事件,都會被放 入執行佇列中等待。

      關於Js的阻塞機制,可以看下面一段程式碼,一般,我們會認為,這段程式碼會log出來0,1,2

for(var i = 0; i < 3; i++) {
    setTimeout(function() {
        console.log(i);
    }, (i + 1) * 1000);
}

      而實際上,這段程式碼log出來的結果是 3,3,3。這是js新手很容易遇到的問題,具體原因就是因為for迴圈的阻塞機制。在上面的程式碼中,setTimeout這個定時器需要等待for迴圈 執行完成,而for迴圈執行完成了之後,i已經為3了,此時才開始執行setTimeout,因此console.log(i)會是3。

      至於為什麼i會是3,請回顧一下for迴圈的執行順序,當i為2的時候,滿足迴圈條件,執行程式碼塊,然後i++,此時i為3,不滿足迴圈條件,不執行程式碼塊,迴圈停止。

      對於for迴圈,記住,是在不滿足條件的情況下停止迴圈,對於以上程式碼,可以看出,i=3的時候才不滿足。

怎麼解決事件阻塞

      其實,阻塞作為js引擎的處理方式,我們最好不要想著解決“阻塞”,而是讓我們想執行的程式碼,插入到“主執行緒”中。這麼說比較不易理解,還是以上面的程式碼為例,直接上程式碼好了

for(var i = 0; i < 3; i++) {
    (function(i) {
        setTimeout(function() {
            console.log(i);
        }, (i + 1) * 1000);
    })(i)
}

      再上面的程式碼中,我們加了一個立即執行的匿名函式,並且將for迴圈的i作為實參傳入進去。這樣,setTimeout就會被立即執行,而不會等待(這裡不太瞭解細節,就不多說了,大概猜測為新開了一個臨時的執行緒,立即執行匿名函式,然後再立即切換回來)。

      本文主要在說明如何解決這一類問題,對於底層原理,還待繼續挖掘。

      注意:html5支援Web worker功能,可以寫多執行緒