147

下面的這個函數不能像我想要的那樣工作 - 作爲一個JS新手我無法弄清楚爲什麼。Javascript - 在執行下一行之前等待5秒鐘

我需要它等5秒鐘,然後檢查newState是否爲-1。

目前,它不等,它只是馬上檢查。

function stateChange(newState) { 
    setTimeout('', 5000); 

    if(newState == -1) { 
    alert('VIDEO HAS STOPPED'); 
    } 
} 

回答

190

你必須把你的代碼在你提供給setTimeout回調函數:

function stateChange(newState) { 
    setTimeout(function() { 
     if (newState == -1) { 
      alert('VIDEO HAS STOPPED'); 
     } 
    }, 5000); 
} 

任何其他代碼將立即執行。

+2

的主要問題是,在某些情況下(特別測試),這是可悲的不足。 如果您在從函數返回之前需要睡500ms,例如模擬_slow_ async http請求,該怎麼辦? –

+6

如果通過「測試」,你的意思是單元測試:你的測試框架應該有一種方法來運行異步測試。如果您指的是手動測試:Chrome的網絡標籤有一個Throttling下拉菜單來模擬緩慢的請求。 –

26

你不應該試着在JavaScript中暫停5秒。它不這樣工作。您可以安排一段代碼函數,從現在開始運行5秒,但您必須將稍後要運行的代碼放入函數中,並且在該函數後的其餘代碼將繼續立即運行。

例如:

function stateChange(newState) { 
    setTimeout(function(){ 
     if(newState == -1){alert('VIDEO HAS STOPPED');} 
    }, 5000); 
} 

但是,如果你有這樣的代碼:

stateChange(-1); 
console.log("Hello"); 

console.log()語句將立即運行。它不會等到stateChange()函數中的超時觸發後。你不能只是暫停JavaScript執行一段預定的時間。

相反,任何想要運行延遲的代碼都必須位於setTimeout()回調函數內(或從該函數調用)。

如果你確實試圖通過循環「暫停」,那麼你基本上會「掛」Javascript解釋器一段時間。因爲Javascript只在一個線程中運行你的代碼,所以當你循環時,其他任何事件處理程序都不能被調用。因此,等待某個變量進行循環更改將無法工作,因爲沒有其他代碼可以運行來更改該變量。

+26

**你不能只是暫停JavaScript執行一段預定的時間**。我認爲你的意思是你不應該,因爲你*可以*(如果你想掛你自己):'var t = new Date()。getTime(); while(new Date()。getTime()

+9

@JosephSilber - 好的,你可以這樣做,但實際上這並不起作用,因爲許多瀏覽器會提出一個對話說腳本有變得沒有響應,這是一個可怕的用戶體驗,這對電池壽命是不利的,並且頁面在這樣做時被掛起,並且...這會很糟糕。 – jfriend00

+10

那麼當然*這將是可怕的,沒有人會永遠永遠做到這一點。我無法抗拒我內心的[「實際上」](http://tirania.org/blog/archive/2011/Feb-17.html)。抱歉。 –

18

使用延時功能是這樣的:

var delay = (function() { 
    var timer = 0; 
    return function(callback, ms) { 
     clearTimeout (timer); 
     timer = setTimeout(callback, ms); 
    }; 
})(); 

用法:

delay(function(){ 
    // do stuff 
}, 600); // end delay 

現金轉到用戶的CMS,請參閱創建等待這樣的功能How to delay the .keyup() handler until the user stops typing?

+0

我沒有看到任何jQuery。 –

+0

好點,謝謝。編輯。 –

7

的最佳方式毫秒,該函數將等待參數中提供的毫秒數:

function waitSeconds(iMilliSeconds) { 
 
    var counter= 0 
 
     , start = new Date().getTime() 
 
     , end = 0; 
 
    while (counter < iMilliSeconds) { 
 
     end = new Date().getTime(); 
 
     counter = end - start; 
 
    } 
 
}

87

你真的不應該這樣做,正確的使用超時對於OP的問題,任何其他場合,你只需要運行一段時間後,一些合適的工具。 Joseph Silber在他的回答中已經證明了這一點。但是,如果在一些非生產的情況下,你想要掛一段時間的主線程,這將做到這一點。

function wait(ms){ 
    var start = new Date().getTime(); 
    var end = start; 
    while(end < start + ms) { 
    end = new Date().getTime(); 
    } 
} 

與表單執行:

console.log('before'); 
wait(7000); //7 seconds in milliseconds 
console.log('after'); 

我來到這裏是因爲我是建立一個簡單的測試用例測序異步操作的混合周圍長時間運行的阻塞操作(即昂貴的DOM操縱),這是我的模擬阻止操作。它適合那個工作,所以我想我會把它發佈給任何其他人,他們在這裏以類似的用例來到這裏。即便如此,它在while循環中創建了一個Date()對象,如果運行時間足夠長,它可能會壓倒GC。但我不能強調,這隻適合測試,建立任何實際的功能,你應該參考約瑟夫西爾伯的答案。

+3

這不會阻止JavaScript執行。 –

+9

@TerryLin嘗試運行它。 – Mic

+2

所以基本上你在浪費CPU時間。這不是一個等待,因爲您不會將線程置於睡眠模式,從而允許主處理器專注於其他任務。 – Kyordhel

7

試試這個:

//the code will execute in 1 3 5 7 9 seconds later 
function exec() { 
    for(var i=0;i<5;i++) { 
     setTimeout(function() { 
      console.log(new Date()); //It's you code 
     },(i+i+1)*1000); 
    } 
} 
+3

將不起作用。主代碼將繼續執行 – nyet

3

基於約瑟夫·西爾伯的answer,我會那樣做,有點更通用。

你將有你的函數(讓我們創建一個基於問題之一):

function videoStopped(newState){ 
    if (newState == -1) { 
     alert('VIDEO HAS STOPPED'); 
    } 
} 

而且你可以有一個等待功能:

function wait(milliseconds, foo, arg){ 
    setTimeout(function() { 
     foo(arg); // will be executed after the specified time 
    }, milliseconds); 
} 

在最後你將有:

wait(5000, videoStopped, newState); 

這是一個解決方案,我寧願不在等待函數中使用參數(只有foo();而不是foo(arg);),但這是例子。

-1

使用angularjs:

$timeout(function(){ 
if(yourvariable===-1){ 
doSomeThingAfter5Seconds(); 
} 
},5000) 
5

下面是使用新async/await語法的解決方案。

一定要檢查browser support,因爲這是ECMAScript中引入的新功能6.

const wait = (ms) => { 
    return new Promise((resolve) => { 
    setTimeout(resolve, ms); 
    }); 
} 

用法:

async function yourFunction() { 
    await wait(5000); 
    console.log("Waited 5s"); 
} 
+0

它不起作用 – Ivan

+0

@Ivan在我的答案中提供的鏈接中查看瀏覽器支持。 –

+0

不需要ECMAScript 6:如果您正在使用承諾來執行異步加載,並且只是想花費很長時間模仿鏈的一部分,則可以將此wait()函數添加到鏈中。 –

相關問題