Javascript 代码执行中的同步延迟
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6921895/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Synchronous delay in code execution
提问by kavita
I have a code which needs to be executed after some delay say 5000 ms.Currently I am using setTimeout but it is asynchronous and i want the execution to wait for its return. I have tried using the following:
我有一个代码需要在一些延迟后执行,比如 5000 毫秒。目前我正在使用 setTimeout 但它是异步的,我希望执行等待它的返回。我尝试使用以下方法:
function pauseComp(ms)
{
var curr = new Date().getTime();
ms += curr;
while (curr < ms) {
curr = new Date().getTime();
}
}
But the code i want to delay is drawing some objects using raphaeljs and the display is not at all smooth. I am trying to use doTimeout plugin. I need to have a delay only once as the delay and code to be delayed are both in a loop. I have no requirement for a id so I am not using it. For example:
但是我想延迟的代码是使用 raphaeljs 绘制一些对象,并且显示一点也不流畅。我正在尝试使用 doTimeout 插件。我只需要延迟一次,因为延迟和要延迟的代码都在循环中。我对 id 没有要求,所以我没有使用它。例如:
for(i; i<5; i++){ $.doTimeout(5000,function(){
alert('hi'); return false;}, true);}
This waits for 5 sec befor giving first Hi and then successive loop iterations show alert immediately after the first. What I want it to do is wait 5 sec give alert again wait and then give alert and so on.
这等待 5 秒前给出第一个 Hi,然后连续循环迭代在第一个之后立即显示警报。我想要它做的是等待 5 秒再次发出警报等待然后发出警报等等。
Any hints/ suggestions are appreciated!
任何提示/建议表示赞赏!
回答by ThinkBonobo
Variation on the accepted answer which is just as good as this one.
接受的答案的变化与这个答案一样好。
Also, I agree with the caveats of preferring setTimeout
and asynchronous function calling but sometimes e.g., when building tests, you just need a synchronous wait command...
此外,我同意首选setTimeout
和异步函数调用的警告,但有时例如,在构建测试时,您只需要一个同步等待命令......
function wait(ms) {
var start = Date.now(),
now = start;
while (now - start < ms) {
now = Date.now();
}
}
if you want it in seconds, divide start ms by 1000 on the while check...
如果你想以秒为单位,在 while 检查中将 start ms 除以 1000 ......
回答by michael_olofinjana
If you'd like to take advantage of the new async/await syntax, You can convert set timeout to a promise and then await it.
如果您想利用新的 async/await 语法,您可以将设置超时转换为承诺,然后等待它。
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!")
})();
回答by Lin
Synchronous wait (only for testing!):
同步等待(仅用于测试!):
const syncWait = ms => {
const end = Date.now() + ms
while (Date.now() < end) continue
}
Usage:
用法:
console.log('one')
syncWait(5000)
console.log('two')
Asynchronous wait:
异步等待:
const asyncWait = ms => new Promise(resolve => setTimeout(resolve, ms))
Usage:
用法:
(async () => {
console.log('one')
await asyncWait(5000)
console.log('two')
})()
Alternative (asynchronous):
替代(异步):
const delayedCall = (array, ms) =>
array.forEach((func, index) => setTimeout(func, index * ms))
Usage:
用法:
delayedCall([
() => console.log('one'),
() => console.log('two'),
() => console.log('three'),
], 5000)
回答by OverZealous
JavaScript is a single-threaded language. You cannot combine setTimeout
and synchronous processing. What will happen is, the timer will lapse, but then the JS engine will wait to process the results until the current script completes.
JavaScript 是一种单线程语言。你不能结合setTimeout
和同步处理。将会发生的情况是,计时器将失效,但随后 JS 引擎将等待处理结果,直到当前脚本完成。
If you want synchronous methods, just call the method directly!
如果要同步方法,直接调用方法即可!
If you want to process something after the setTimeout, include it or call it from the timeout function.
如果您想在 setTimeout 之后处理某些内容,请包含它或从 timeout 函数中调用它。
回答by nnnnnn
Non-timeout loops (that check the time or count to 1000000 or whatever) just lock up the browser. setTimeout
(or the $.doTimeout
plugin) is the best way to do it.
非超时循环(检查时间或计数到 1000000 或其他)只会锁定浏览器。setTimeout
(或$.doTimeout
插件)是最好的方法。
Creating timeouts within a loop won't work because the loop doesn't wait for the previous timeout to occur before continuing, as you've discovered. Try something more like this:
如您所见,在循环中创建超时将不起作用,因为循环在继续之前不会等待前一个超时发生。尝试更像这样的事情:
// 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);
(I just cobbled this together quickly, so although I'm confident that it works it could be improved in several ways, e.g., within the "loop" it could pass an index value into the callback function so that your own code knows which iteration it is up to. But hopefully it will get you started.)
(我只是快速拼凑起来,所以虽然我相信它可以工作,但可以通过多种方式改进,例如,在“循环”中,它可以将索引值传递给回调函数,以便您自己的代码知道哪个迭代这取决于。但希望它能让你开始。)
回答by andrew65952
I have made a simple synchronous timeout function. It works in two different ways, callback and non-callback.
我做了一个简单的同步超时函数。它以两种不同的方式工作,回调和非回调。
function:
功能:
function wait(ms, cb) {
var waitDateOne = new Date();
while ((new Date()) - waitDateOne <= ms) {
//Nothing
}
if (cb) {
eval(cb);
}
}
callback example:
回调示例:
wait(5000,"doSomething();");
non-callback example:
非回调示例:
console.log("Instant!");
wait(5000);
console.log("5 second delay");
回答by user2314737
Here's how you can use the JQuery doTimeout
plugin
以下是如何使用 JQuerydoTimeout
插件
jQuery('selector').doTimeout( [ id, ] delay, callback [, arg ... ] );
From the docs: "If the callback returns true, thedoTimeout
loop will execute again, after the delay, creating a polling loop until the callback returns a non-true value."
来自文档:“如果回调返回真,doTimeout
循环将再次执行,延迟后,创建一个轮询循环,直到回调返回一个非真值。”
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>
回答by Peter L
Node solution
节点解决方案
Use fs.existsSync() to delay
使用 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());
}
回答by kemicofa ghost
Solution using function generators. To show that it can be done. Not recommended.
使用函数生成器的解决方案。以表明它可以做到。不推荐。
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");