151

有没有一种方法可以在 JavaScript 执行另一个操作之前让它进入睡眠状态?

例子:

 var a = 1+3;
 // Sleep 3 seconds before the next action here
 var b = a + 4;
4

14 回答 14

156

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

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

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

于 2009-04-17T01:37:36.717 回答
71

如果你真的需要一个sleep()只是为了测试一些东西。但是请注意,它在调试时大多数时候都会使浏览器崩溃——这可能就是你需要它的原因。在生产模式下,我将注释掉这个函数。

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

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

于 2015-01-09T22:20:50.737 回答
16

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

功能*

() => 箭头函数

您还可以通过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
)

于 2016-06-28T19:22:57.500 回答
13

2018 更新

最新的 Safari、Firefox 和 Node.js 现在也支持 async/await/promises。

使用异步/等待/承诺:

(截至 1/2017,在 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() 不同?请求者要求真正的睡眠(进程上没有其他代码执行)而不是动作之间的延迟。

于 2017-01-11T18:04:33.943 回答
4

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

async yourAsynchronousFunction () {

    var a = 1+3;

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

    var b = a + 4;

}
于 2018-08-30T07:27:52.510 回答
4

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

于 2019-08-05T18:28:03.487 回答
3

如果你想要比setTimeoutand更少笨重的函数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 毫秒,...”)

于 2016-07-16T03:43:51.083 回答
2

您可以使用纯 javascript,这将在 5 秒后调用您的函数/方法:

setTimeout(()=> { your_function(); }, 5000);
于 2020-04-03T16:57:06.333 回答
1

您可以使用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');
于 2019-03-16T04:15:22.297 回答
1

这是使用调用 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"));

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

于 2020-12-15T23:27:51.107 回答
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()

于 2020-12-19T04:06:07.577 回答
1

为了什么值得

  isPause = true;
  setTimeout(()=>{isPause=false},2000);
  while (!isPause) {
    // delay for 2 seconds
  }
    
于 2021-09-23T07:02:32.667 回答
0

有几种方法可以解决这个问题。如果我们使用该setTimeout功能,让我们先了解它。 这个函数有三个参数:functionor code, delay(以毫秒为单位)和parameters. 由于函数代码参数是必需的,其他都是可选的。一旦您没有输入延迟,它将被设置为零。

有关setTimeout() 转到此链接的更多详细信息。

简化版:

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
于 2017-07-31T17:10:59.697 回答
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>
于 2018-06-10T00:50:02.340 回答