在 JavaScript 中休眠 - 动作之间的延迟
Posted
技术标签:
【中文标题】在 JavaScript 中休眠 - 动作之间的延迟【英文标题】:Sleep in JavaScript - delay between actions 【发布时间】:2010-10-20 00:15:17 【问题描述】:有没有一种方法可以在 javascript 执行其他操作之前让其休眠?
例子:
var a = 1+3;
// Sleep 3 seconds before the next action here
var b = a + 4;
【问题讨论】:
【参考方案1】:你可以使用setTimeout
来达到类似的效果:
var a = 1 + 3;
var b;
setTimeout(function()
b = a + 4;
, (3 * 1000));
这并不是真正的“睡眠”JavaScript——它只是在一定的持续时间(以毫秒为单位)后执行传递给setTimeout
的函数。虽然可以为 JavaScript 编写睡眠函数,但最好尽可能使用setTimeout
,因为它不会在睡眠期间冻结所有内容。
【讨论】:
还可以查看 setInterval()。它类似于 setTimeout(),但你的函数被多次调用(直到你停止它),如果你想在睡觉时做一些事情(比如做进度更新、保持一些内部状态等等),这很有用。 这不能回答问题。这个问题要求一个“睡眠”等价物,这不是。 虽然这个答案与问题的答案不符,但它比循环和比较 Date.now() 更有用。没有人使用阻塞循环执行睡眠。 当然,除非阻塞循环正是有人想要的。【参考方案2】:如果您真的需要 sleep()
来测试某些东西。但是请注意,它在调试时大多数时候都会使浏览器崩溃——这可能就是你需要它的原因。在生产模式下我会注释掉这个函数。
function pauseBrowser(millis)
var date = Date.now();
var curDate = null;
do
curDate = Date.now();
while (curDate-date < millis);
不要在循环中使用new Date()
,除非您想浪费内存、处理能力、电池以及可能的设备寿命。
【讨论】:
这个答案值得更多投票。为这个问题加注星标只是这个答案的原因。 @OkiErieRinaldi 那里没有递归,它只是一个循环。 @3.1415926535897932384626433833 好吧,有人要求提供“睡眠”功能,这就是这里。我用过一次,不记得具体是为了什么调试。如果我再次需要它,我知道在哪里可以找到它。如果您更喜欢其他功能,那是您的选择。能够选择是不是很棒? “正在等待”。 您一直在制造的忙碌等待循环完全符合您的期望:它将耗尽处理能力、电池,并可能耗尽您设备的使用寿命。它可能比new Date()
使用内存,但这也可能取决于实现。可以调试代码,但甚至不要考虑将它用于任何中途生产的事情。【参考方案3】:
ECMAScript 6 版本,使用带有 yield 的生成器进行“代码阻塞”:
因为最初的问题是七年前发布的,所以我没有费心回答确切的代码,因为它太简单了而且已经回答了。这应该有助于解决更复杂的问题,例如您是否需要至少两次睡眠,或者您计划对异步执行进行排序。随意修改它以满足您的需求。
let sleeptime = 100
function* clock()
let i = 0
while( i <= 10000 )
i++
console.log(i); // actually, just do stuff you wanna do.
setTimeout(
()=>
clk.next()
, sleeptime
)
yield
let clk = clock()
clk.next()
function*
() => arrow function
您也可以通过Promises链接事件:
function sleep(ms)
return(
new Promise(function(resolve, reject)
setTimeout(function() resolve(); , ms);
)
);
sleep(1000).then(function()
console.log('1')
sleep(1000).then(function()
console.log('2')
)
)
或者更简单、不那么花哨的方式
function sleep(ms, f)
return(
setTimeout(f, ms)
)
sleep(500, function()
console.log('1')
sleep(500, function()
console.log('2')
)
)
console.log('Event chain launched')
如果你只是在等待某种情况发生,你可以这样等待
function waitTill(condition, thenDo)
if (eval(condition))
thenDo()
return
setTimeout(
() =>
waitTill(condition, thenDo)
,
1
)
x=0
waitTill(
'x>2 || x==1'
,
() =>
console.log("Conditions met!")
)
// Simulating the change
setTimeout(
() =>
x = 1
,
1000
)
【讨论】:
【参考方案4】:如果您想要比setTimeout
和setInterval
更少笨重的函数,您可以将它们包装在只颠倒参数顺序并给它们起好名字的函数中:
function after(ms, fn) setTimeout(fn, ms);
function every(ms, fn) setInterval(fn, ms);
CoffeeScript 版本:
after = (ms, fn)-> setTimeout fn, ms
every = (ms, fn)-> setInterval fn, ms
然后您可以将它们与匿名函数很好地结合使用:
after(1000, function()
console.log("it's been a second");
after(1000, function()
console.log("it's been another second");
);
);
现在它很容易读为“N 毫秒后,...”(或“每 N 毫秒,...”)
【讨论】:
【参考方案5】:2018 年更新
最新的 Safari、Firefox 和 Node.js 现在也支持 async/await/promises。
使用 async/await/Promises:
(自 2017 年 1 月起,在 Chrome 上受支持,但在 Safari、Internet Explorer、Firefox、Node.js 上不支持)
'use strict';
function sleep(ms)
return new Promise(res => setTimeout(res, ms));
let myAsyncFunc = async function()
console.log('Sleeping');
await sleep(3000);
console.log('Done');
myAsyncFunc();
2017 年更新
自从提出这个问题以来,JavaScript 已经发展,现在有了生成器函数,并且正在推出新的 async/await/Promise。 下面有两种解决方案,一种具有适用于所有现代浏览器的生成器功能,另一种使用尚不支持的新 async/await。
使用生成器函数:
'use strict';
let myAsync = (g) => (...args) =>
let f, res = () => f.next(),
sleep = (ms) => setTimeout(res, ms);
f = g.apply(sleep, args); f.next();
;
let myAsyncFunc = myAsync(function*()
let sleep = this;
console.log("Sleeping");
yield sleep(3000);
console.log("Done");
);
myAsyncFunc();
请注意,这两种解决方案本质上都是异步的。这意味着 myAsyncFunc(在这两种情况下)将在睡眠时返回。
请务必注意,此问题不同于 What is the JavaScript version of sleep()?,其中请求者请求的是真正的睡眠(进程上没有其他代码执行),而不是动作之间的延迟。 p>
【讨论】:
迄今为止最好的答案!!我花了 30 分钟到处搜索以找到那个.. 非常感谢 !!! 我在寻找解决方案并重新发明了自行车时错过了这个答案:D 如果我能在它节省我几个小时之前看到它!点赞!let co = gen => (...args) => let iter = gen(...args); let resume = () => new Promise((resolve, reject) => let result = iter.next(); if (result.done) resolve(result.value); else Promise.resolve(result.value).then(resume).then(resolve, reject); ); return resume(); ;
会让您使用第二个代码块中的sleep()
定义来执行let asyncAdd = co(function* (a, b) console.log('Sleeping'); yield sleep(3000); console.log('Done'); return a + b; ); asyncAdd(3, 4).then(console.log);
。【参考方案6】:
有几种方法可以解决这个问题。如果我们使用setTimeout
函数,我们先来了解一下。
This function 具有三个参数:function
或 code
、delay
(以毫秒为单位)和 @987654327 @。
由于 function 或 code 参数是必需的,因此其他参数是可选的。
一旦你没有输入延迟,它将被设置为零。
有关setTimeout()
go to this link的更多详细信息。
简化版:
var a = 1 + 3;
var b;
console.log('a = ' + a);
setTimeout(function()
b = a + 4;
console.log('b = ' + b);
, 1000);
输出: a = 4 24 --> 活动超时列表的编号标识符 b = 8
使用参数传递:
var a = 1 + 3;
var b;
console.log('a = ' + a);
setTimeout(myFunction, 1000, a);
function myFunction(a)
var b = a + 4;
console.log('b = ' + b);
输出: a = 4 25 --> 活动超时列表的编号标识符 b = 8
浏览器支持:
Chrome 火狐边缘 Safari Opera 1.0 1.0 4.0 1.0 4.0【讨论】:
【参考方案7】:这是我的模型,展示了如何使用生成器函数 (ES6) 在 javascript 中“休眠”或“DoEvents”。注释代码:
<html>
<head>
<script>
"use strict"; // always
// Based on post by www-0av-Com https://***.com/questions/3143928
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*
var divelt, time0, globaln = 0; // global variables
var MainGenObj = Main(); // generator object = generator function()
window.onload = function()
divelt = document.getElementsByTagName("body")[0]; // for addline()
addline("typeof Main: " + typeof Main);
addline("typeof MainDriver: " + typeof MainDriver);
addline("typeof MainGenObj: " + typeof MainGenObj);
time0 = new Date().valueOf(); // starting time ms
MainDriver(); // do all parts of Main()
function* Main() // this is "Main" -- generator function -- code goes here
// could be loops, or inline, like this:
addline("Part A, time: " + time() + ", " + ++globaln); // part A
yield 2000; // yield for 2000 ms (like sleep)
addline("Part B, time: " + time() + ", " + ++globaln); // part B
yield 3000; // yield for 3000 ms (or like DoEvents)
addline("Part Z, time: " + time() + ", " + ++globaln); // part Z (last part)
addline("End, time: " + time());
function MainDriver() // this does all parts, with delays
var obj = MainGenObj.next(); // executes the next (or first) part of Main()
if (obj.done == false) // if "yield"ed, this will be false
setTimeout(MainDriver, obj.value); // repeat after delay
function time() // seconds from time0 to 3 decimal places
var ret = ((new Date().valueOf() - time0)/1000).toString();
if (ret.indexOf(".") == -1) ret += ".000";
while (ret.indexOf(".") >= ret.length-3) ret += "0";
return ret;
function addline(what) // output
divelt.innerHTML += "<br />\n" + what;
</script>
</head>
<body>
<button onclick="alert('I\'m alive!');"> Hit me to see if I'm alive </button>
</body>
</html>
【讨论】:
【参考方案8】:另一种方法是使用 Promise 和 setTimeout(请注意,您需要在函数内部并使用 async 关键字将其设置为异步):
async yourAsynchronousFunction ()
var a = 1+3;
await new Promise( (resolve) =>
setTimeout( () => resolve(); , 3000);
var b = a + 4;
【讨论】:
【参考方案9】:您可以使用setTimeout
在指定时间后调用回调:
setTimeout(() =>
console.log('Called after 1 second');
, 1000);
如果你想使用setTimeout
作为一个承诺,你可以这样做:
const delay = milliseconds => new Promise(resolve => setTimeout(resolve, milliseconds); );
await delay(1000);
console.log('Called after 1 second');
从 Node.js 16 开始,这个功能也是built-in:
import setTimeout as delay from 'node:timers/promises';
await delay(1000);
console.log('Called after 1 second');
如果你想在 Node.js 或浏览器中在主线程之外实现同步延迟,you can use Atomics.wait
:
const delay = milliseconds => Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, milliseconds);
await delay(1000);
console.log('Called after 1 second');
【讨论】:
我喜欢它的优雅简洁。这是一条线。感人的。我送你一杯你选择的虚拟啤酒。 ?【参考方案10】:这是一种非常简单的方法,它“感觉”像同步睡眠/暂停,但却是合法的 js 异步代码。
// Create a simple pause function
const pause = (timeoutMsec) => new Promise(resolve => setTimeout(resolve,timeoutMsec))
async function main ()
console.log('starting');
// Call with await to pause. Note that the main function is declared asyc
await pause(3*1000)
console.log('done');
【讨论】:
【参考方案11】:您可以使用纯 javascript,这将在 5 秒后调用您的函数/方法:
setTimeout(()=> your_function(); , 5000);
【讨论】:
【参考方案12】:这是一个使用调用 setTimeout() 的基于 Promise 的 sleep() 的重写和演示。它还演示了对 setTimeout() 的常规调用。
function sleep(ms)
return new Promise(resolve => setTimeout(() => resolve(), ms))
console.log("Synchronous call");
sleep(2000)
.then(() => console.log("Asynchronous call"));
Image of its run on Repl.it
function sleep(ms)
return new Promise(resolve => setTimeout(() => resolve(), ms))
console.log("Synchronous call 1");
sleep(4000)
.then(() => console.log("Asynchronous call 1"));
sleep(2000)
.then(() => console.log("Asynchronous call 2"));
console.log("Synchronous call 2");
sleep(3000)
.then(() => console.log("Asynchronous call 3"));
console.log("Synchronous call 3");
sleep(5000)
.then(() => console.log("Asynchronous call 4"))
.then(
sleep(7000)
.then(()=>console.log("Asynchronous call 5"))
)
console.log("Synchronous call 4");
setTimeout(() => console.log("Asynchronous call 6"), 8000);
console.log("Synchronous call 5");
【讨论】:
【参考方案13】:function delayer(ms)
return new Promise((resolve, reject)=>
setTimeout(()=>
resolve();
, ms)
)
async function myFunction() // Function Must be async.
console.log("First Console")
await delayer(2000); // This Will Stop The Code For 2 Seconds
console.log("Second Console")
myFunction()
【讨论】:
【参考方案14】:物有所值
isPause = true;
setTimeout(()=>isPause=false,2000);
while (!isPause)
// delay for 2 seconds
【讨论】:
以上是关于在 JavaScript 中休眠 - 动作之间的延迟的主要内容,如果未能解决你的问题,请参考以下文章