在 JavaScript 中睡眠-动作之间的延迟

在 JavaScript 执行下一个操作之前,有没有什么方法可以让我睡一觉?

例如:

var a = 1 + 3;
// Sleep 3 seconds before the next action here.
var b = a + 4;
115823 次浏览

你可以使用 setTimeout来达到类似的效果:

var a = 1 + 3;
var b;
setTimeout(function() {
b = a + 4;
}, (3 * 1000));

这并不是真正的“睡眠”JavaScript ーー它只是在一定的持续时间(以毫秒为单位)后执行传递给 setTimeout的函数。尽管为 JavaScript 编写一个睡眠函数是可能的,但是如果可能的话,最好使用 setTimeout,因为它不会在睡眠期间冻结所有内容。

以防你真的需要一个 sleep()来测试一些东西。但是请注意,它会崩溃浏览器的大部分时间,而调试-可能这就是为什么你需要它无论如何。在生产模式中,我将注释掉这个函数。

function pauseBrowser(millis) {
var date = Date.now();
var curDate = null;
do {
curDate = Date.now();
} while (curDate-date < millis);
}

不要在循环中使用 new Date(),除非你想浪费内存、处理能力、电池,可能还有设备的使用寿命。

ECMAScript 6版本,使用带有“代码阻塞”的生成器:

因为最初的问题是在七年前发布的,所以我没有用准确的代码来回答,因为它实在是太简单了,而且已经被回答了。这将有助于解决更复杂的问题,比如需要至少两次睡眠,或者计划对异步执行进行排序。请随意修改,以适应您的需要。

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 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
)

如果你想要比 setTimeoutsetInterval简单的函数,你可以把它们包装在函数中,这样可以颠倒参数的顺序,给它们起个好听的名字:

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 毫秒,...”)

2018年最新情况

The latest Safari, Firefox and Node.js are now also supporting 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 自从提出这个问题以来就不断发展,现在已经有了生成器函数,并且新的异步/等待/承诺正在推出。下面有两个解决方案,一个具有生成器功能,可以在所有现代浏览器上工作,另一个使用新的异步/等待,这还不是所有地方都支持的。

使用生成器函数:

'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 (在这两种情况下)将在睡眠时返回。

值得注意的是,这个问题不同于 什么是 JavaScript 版本的 sleep () ,在 什么是 JavaScript 版本的 sleep () 中,请求者要求的是真正的睡眠(在进程中没有其他代码执行) ,而不是动作之间的延迟。

有几种方法可以解决这个问题。如果我们使用 setTimeout函数,让我们先了解它。 这个函数 有三个参数: functioncodedelay(毫秒)和 parameters。 因为 功能密码参数是必需的,所以其他参数是可选的。 一旦您没有输入 推迟,它将被设置为零。

有关 setTimeout() 到这个链接的详细信息。

简化版:

var a = 1 + 3;
var b;
console.log('a = ' + a);
setTimeout(function(){
b = a + 4;
console.log('b = ' + b);
}, 1000);

产出:
A = 4
活动超时列表的编号标识符
B = 8 < br/>


使用参数传递:

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
活动超时列表的编号标识符
B = 8 < br/>



浏览器支持:

Chrome     Firefox     Edge     Safari     Opera
1.0        1.0         4.0      1.0        4.0

这是我的模型,它展示了如何使用生成器函数(ES6)在 javascript 中“睡眠”或“ DoEvents”:

<html>
<head>
<script>
"use strict"; // always
// Based on post by www-0av-Com https://stackoverflow.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>

另一种方法是通过使用  诺言和 setTimeout (注意,您需要位于函数内部,并通过异步关键字将其设置为异步的) :

async yourAsynchronousFunction () {


var a = 1+3;


await new Promise( (resolve) => {
setTimeout( () => { resolve(); }, 3000);
}


var b = a + 4;


}

可以使用 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以来,这个功能也是 内置的:

import {setTimeout as delay} from 'node:timers/promises';


await delay(1000);


console.log('Called after 1 second');

如果你想在 Node.js 或者浏览器 在主线之外中同步延迟,你可以使用 Atomics.wait:

const delay = milliseconds => Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, milliseconds);


await delay(1000);


console.log('Called after 1 second');

这里有一个非常简单的方法,感觉像是同步睡眠/暂停,但是是合法的 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');
}

你可以使用普通的 javascript,它会在5秒后调用你的函数/方法:

setTimeout(()=> { your_function(); }, 5000);

下面是使用对 setTimeout ()的调用来重写和演示基于承诺的 sleep ()。它还演示了对 setTimeout ()的常规调用。

function sleep(ms) {
return new Promise(resolve => setTimeout(() => resolve(), ms))
}


console.log("Synchronous call");
sleep(2000)
.then(() => console.log("Asynchronous call"));

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");

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()

无论如何

  isPause = true;
setTimeout(()=>{isPause=false},2000);
while (!isPause) {
// delay for 2 seconds
}
    

我知道这个问题很老套但如果有人在找这个, 有一种更清晰的方式,可以使用承诺在 javascript 中睡眠

function sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}


const run = async () => {
while(true){
console.log("yay1")
await sleep(3000)
console.log("next action")
}
}


run()


在第一个日志和第二个日志之间总是有3秒的暂停时间

这里发生的是,

  1. 使用 等待,JavaScript 的代码执行会暂停,直到 承诺已经兑现。

  2. 当解析器被激发时,承诺将被解决 在执行 setTimeout 时将触发解析器。

  3. SetTimeout 将在给定持续时间后执行,单位为毫秒。