[英]Synchronous delay in code execution
我有一個代碼需要在延遲 5000 毫秒后執行。目前我正在使用 setTimeout 但它是異步的,我希望執行等待它返回。 我嘗試使用以下內容:
function pauseComp(ms)
{
var curr = new Date().getTime();
ms += curr;
while (curr < ms) {
curr = new Date().getTime();
}
}
但是我想延遲的代碼是使用 raphaeljs 繪制一些對象並且顯示一點也不流暢。 我正在嘗試使用 doTimeout 插件。 我只需要延遲一次,因為延遲和要延遲的代碼都在一個循環中。 我不需要 ID,所以我沒有使用它。 例如:
for(i; i<5; i++){ $.doTimeout(5000,function(){
alert('hi'); return false;}, true);}
這等待 5 秒,然后給出第一個 Hi,然后連續的循環迭代在第一個之后立即顯示警報。 我想讓它做的是等待 5 秒再次發出警報等待然后發出警報等等。
任何提示/建議表示贊賞!
接受的答案的變化與這個一樣好。
此外,我同意優先使用setTimeout
和異步函數調用的警告,但有時,例如,在構建測試時,您只需要一個同步等待命令......
function wait(ms) {
var start = Date.now(),
now = start;
while (now - start < ms) {
now = Date.now();
}
}
如果你想在幾秒鍾內得到它,在 while 檢查中將 start ms 除以 1000...
如果您想利用新的 async/await 語法,您可以將 set timeout 轉換為 Promise,然后等待它。
function wait(ms) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("Done waiting");
resolve(ms)
}, ms )
})
}
(async function Main() {
console.log("Starting...")
await wait(5000);
console.log("Ended!")
})();
const syncWait = ms => {
const end = Date.now() + ms
while (Date.now() < end) continue
}
用法:
console.log('one')
syncWait(5000)
console.log('two')
const asyncWait = ms => new Promise(resolve => setTimeout(resolve, ms))
用法:
(async () => {
console.log('one')
await asyncWait(5000)
console.log('two')
})()
const delayedCall = (array, ms) =>
array.forEach((func, index) => setTimeout(func, index * ms))
用法:
delayedCall([
() => console.log('one'),
() => console.log('two'),
() => console.log('three'),
], 5000)
使用新的 Atomics API,您可以啟動同步延遲而不會出現性能峰值:
const sleep = milliseconds => Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, milliseconds)
sleep(5000) // Sleep for 5 seconds
console.log("Executed after 5 seconds!")
JavaScript 是一種單線程語言。 您不能將setTimeout
和同步處理結合起來。 會發生的情況是,計時器會超時,但是 JS 引擎會等待處理結果,直到當前腳本完成。
如果要同步方法,直接調用方法即可!
如果您想在 setTimeout 之后處理某些內容,請包含它或從 timeout 函數中調用它。
非超時循環(檢查時間或計數到 1000000 或其他)只是鎖定瀏覽器。 setTimeout
(或$.doTimeout
插件)是最好的方法。
正如您所發現的那樣,在循環中創建超時將不起作用,因為循環不會在繼續之前等待先前的超時發生。 嘗試更多類似的東西:
// Generic function to execute a callback a given number
// of times with a given delay between each execution
function timeoutLoop(fn, reps, delay) {
if (reps > 0)
setTimeout(function() {
fn();
timeoutLoop(fn, reps-1, delay);
}, delay);
}
// pass your function as callback
timeoutLoop(function() { alert("Hi"); },
5,
5000);
(我只是快速拼湊起來,所以雖然我相信它可以工作,但可以通過多種方式進行改進,例如,在“循環”中,它可以將索引值傳遞給回調函數,以便您自己的代碼知道哪個迭代這取決於。但希望它能讓你開始。)
我做了一個簡單的同步超時功能。 它以兩種不同的方式工作,回調和非回調。
功能:
function wait(ms, cb) {
var waitDateOne = new Date();
while ((new Date()) - waitDateOne <= ms) {
//Nothing
}
if (cb) {
eval(cb);
}
}
回調示例:
wait(5000,"doSomething();");
非回調示例:
console.log("Instant!");
wait(5000);
console.log("5 second delay");
這是使用 JQuery doTimeout
插件的方法
jQuery('selector').doTimeout( [ id, ] delay, callback [, arg ... ] );
來自文檔:“如果回調返回 true, doTimeout
循環將在延遲后再次執行,創建輪詢循環,直到回調返回非 true 值。 ”
var start = Date.now(); console.log("start: ", Date.now() - start); var i = 0; $.doTimeout('myLoop', 5000, function() { console.log(i+1, Date.now() - start); ++i; return i == 5 ? false : true; });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-dotimeout/1.0/jquery.ba-dotimeout.min.js"></script>
在javascript中做同步延遲是不可能的,僅僅因為javascript是單線程語言。 瀏覽器(最常見的 JS 運行環境)有所謂的event loop
。 所以瀏覽器所做的一切都發生在這個循環中。 當您在瀏覽器中執行腳本時,會發生以下情況:
event loop
將繼續運行請注意,所有這些都發生在event loop
的單個幀中! 這意味着在腳本退出之前不會發生其他操作(如渲染、檢查用戶輸入等)。 (*) async
JavaScript 例外,例如setTimeout/Interval()
或requestAnimationFrame()
,它們不在主線程上運行。 所以從event loop
來看,腳本已經運行完畢。
這意味着如果 JavaScript 中存在同步延遲,整個瀏覽器將不得不等待延遲結束,同時它什么也做不了。 所以沒有,而且JS中也不會有任何同步延遲。
替代方案取決於您想要做的實際事情。 就我而言,我有一個requestAnimationFrame()
循環。 所以我需要做的就是存儲時間,並在循環中檢查舊時間和新時間。
let timer =
{
startTime: 0,
time: 1000, // time for the counter in milliseconds
restart: true // at the beginning, in order to set startTime
};
loop();
function loop()
{
if(timer.restart === true)
{
timer.startTime = Date.now();
timer.restart = false;
}
if((Date.now() - timer.startTime) >= timer.time)
{
timer.restart = true;
console.log('Message is shown every second');
// here put your logic
}
requestAnimationFrame(loop);
}
受 @andrew65952 啟發,但更現代、更快
function wait(ms) {
const now = Date.now()
while (Date.now() - now <= ms) { /* do nothing */}
}
使用函數發生器的解決方案。 表明它可以做到。 不推薦。
function wait(miliseconds){ const gen = function * (){ const end = Date.now() + miliseconds; while(Date.now() < end){yield}; return; } const iter = gen(); while(iter.next().done === false); } console.log("done 0"); wait(1000); console.log("done 1"); wait(2000); console.log("done 2");
節點解決方案
使用 fs.existsSync() 來延遲
const fs = require('fs');
const uuidv4 = require('uuid/v4');
/**
* Tie up execution for at-least the given number of millis. This is not efficient.
* @param millis Min number of millis to wait
*/
function sleepSync(millis) {
if (millis <= 0) return;
const proceedAt = Date.now() + millis;
while (Date.now() < proceedAt) fs.existsSync(uuidv4());
}
fs.existsSync(uuidv4())旨在做一些事情:
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.