JavaScript中的Sleep - 操作之间的延迟

163

在 JavaScript 中,是否有办法在执行另一个操作之前进行睡眠操作?

例子:

var a = 1 + 3;
// Sleep 3 seconds before the next action here.
var b = a + 4;
15个回答

163

你可以使用setTimeout来实现类似的效果:

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

这并不是真正的暂停JavaScript-它只是在一定时间(以毫秒为单位)后执行传递给setTimeout函数的功能。虽然可以为JavaScript编写一个睡眠函数,但最好尽可能使用setTimeout,因为它在睡眠期间不会冻结所有内容。


10
也要看一下setInterval()。它与setTimeout()类似,但您的函数会被多次调用(直到您停止它),如果您想在休眠时执行某些操作(例如进行进度更新、保持内部状态等),这将非常有用。 - Anders Sandvig
9
这并没有回答问题。问题要求一个类似于“睡眠”的替代方案,而这个不是。 - felwithe
虽然这个答案与问题所问不符,但它比循环和比较Date.now()更有用。没有人想使用阻塞循环来实现睡眠。 - Li Chunlin
2
当然,除非有人确实需要一个阻塞循环。 - Wonko the Sane

75

如果你真的需要一个sleep()来测试某些东西,但请注意,在调试时它会导致浏览器崩溃 - 也许这就是你需要它的原因。在生产模式中,我将注释掉此函数。

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

除非你想浪费内存、处理能力、电池以及可能会影响设备寿命,否则不要在循环中使用new Date()


10
这个回答值得更多的点赞。因为这个回答,我给问题点了个赞。 - jagc
1
@OkiErieRinaldi 那里没有递归,只有一个循环。 - Rodrigo
7
@3.1415926535897932384626433833 有人要求“睡眠”功能,这就是这里的内容。我曾经使用过它,但不记得具体是用于哪种调试。如果我以后再需要它,我知道在哪里找到它。如果你喜欢另一个功能,那是你的选择。能够选择不是很棒吗? - Rodrigo
2
"忙等待"。 - Zeek2
2
你制造的忙等待循环正好做了你希望它不会做的事情:它将使用处理能力、电池和可能是设备的寿命。它可能比 new Date() 使用更多的内存,但这也可能取决于实现方式。虽然用于调试代码没问题,但在任何半生产环境中都不要考虑使用它。 - Marcel Waldvogel
显示剩余3条评论

17

使用生成器和yield实现“代码阻塞”的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*函数

() => 箭头函数

您还可以通过Promise链式调用事件:

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
)


13

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

需要注意的是,这个问题与“JavaScript版本的sleep()是什么?”不同,那里的请求者要求真正的睡眠(进程中没有其他代码执行),而不是在操作之间延迟。


1
到目前为止,这是最好的答案!! 我花了30分钟四处搜索才找到它.. 非常感谢!!! - TOPKAT
1
在寻找解决方案时,我错过了这个答案,结果又重新发明了自行车:D 如果早点看到它就能为我节省几个小时的时间了!已点赞! - sserzant
让您能够使用第二个代码块中的sleep()定义,将 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(); }; 进行转换,从而使您可以执行 let asyncAdd = co(function* (a, b) { console.log('Sleeping'); yield sleep(3000); console.log('Done'); return a + b; }); asyncAdd(3, 4).then(console.log); - Patrick Roberts

6

下面这种方法非常简单,感觉就像同步的睡眠/暂停一样,但是它实际上是合法的JavaScript异步代码。

// 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');
}


5
另一种方法是使用 Promise 和 setTimeout(注意,您需要在函数内部设置异步并使用 async 关键字):
async yourAsynchronousFunction () {

    var a = 1+3;

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

    var b = a + 4;

}

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

3

这里是一个使用Promise和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");


2
您可以使用纯JavaScript,此代码会在五秒后调用您的函数/方法:
setTimeout(()=> { your_function(); }, 5000);

1

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接