有没有比下面的pausecomp函数(取自此处)更好的方法来设计JavaScript中的睡眠?

function pausecomp(millis)
{
    var date = new Date();
    var curDate = null;
    do { curDate = new Date(); }
    while(curDate-date < millis);
}

这不是JavaScript中的Sleep的重复-动作之间的延迟;我希望在函数的中间有一个真正的睡眠,而不是在代码执行之前有一段延迟。


当前回答

我更喜欢这种功能型的单线睡眠功能:

const sleep = (ms) => new Promise((res) => setTimeout(res, ms, ms));

// usage
async function main() {
  console.log("before");
  const t = await sleep(10_000); /* 10 sec */
  console.log("after " + t);
}
main();

其他回答

实际上,您可以使用与pausecomp函数相同的while循环实现sleep()(这基本上是相同的):

const sleep = (seconds) => {
    const waitUntil = new Date().getTime() + seconds * 1000
    while(new Date().getTime() < waitUntil) {
        // do nothing
    }
}

您可以像这样使用sleep()方法:

const main = () => {
    const a = 1 + 3

    // Sleep 3 seconds before the next action
    sleep(3)
    const b = a + 4

    // Sleep 4 seconds before the next action
    sleep(4)
    const c = b + 5
}

main()

这就是我想象你会使用睡眠功能的方式,而且读起来相对简单。我借鉴了另一篇文章《JavaScript中的睡眠——动作之间的延迟》,以展示您可能打算如何使用它。

不幸的是,你的电脑会变热,所有工作都会受阻。如果在浏览器中运行,该选项卡将停止,用户将无法与页面交互。

如果您将代码重组为异步的,那么您可以将setTimeout()作为与其他文章相同的睡眠函数。

// define sleep using setTimeout
const sleep = (seconds, callback) => setTimeout(() => callback(), seconds * 1000)

const main = () => {
    const a = 1 + 3
    let b = undefined
    let c = undefined

    // Sleep 3 seconds before the next action
    sleep(3, () => {
        b = a + 4

        // Sleep 4 seconds before the next action
        sleep(4, () => {
            c = b + 5
        })
    })
}

main()

正如你所说,这不是你想要的。我修改了Sleep in JavaScript中的示例-动作之间的延迟,以说明为什么会出现这种情况。当您添加更多动作时,要么需要将逻辑拉入单独的函数,要么将代码嵌套得越来越深(回调地狱)。

为了解决“回调地狱”,我们可以使用promise来定义睡眠:

const sleep = (seconds) => new Promise((resolve => setTimeout(() => resolve(), seconds * 1000)))

const main = () => {
    const a = 1 + 3
    let b = undefined
    let c = undefined

    // Sleep 3 seconds before the next action
    return sleep(3)
        .then(() => {
            b = a + 4

            // Sleep 4 seconds before the next action
            return sleep(4)
        })
        .then(() => {
            c = b + 5
        })
}

main()

Promise可以避免深度嵌套,但看起来仍然不像我们最初使用的常规同步代码。我们希望编写看起来同步的代码,但没有任何缺点。

让我们再次使用async/await重写我们的主方法:

const sleep = (seconds) => new Promise((resolve => setTimeout(() => resolve(), seconds * 1000)))

const main = async () => {
    const a = 1 + 3

    // Sleep 3 seconds before the next action
    await sleep(3)
    const b = a + 4

    // Sleep 4 seconds before the next action
    await sleep(4)
    const c = b + 5
}

main()

使用async/await,我们可以调用sleep(),就好像它是一个同步的阻塞函数一样。这解决了您可能在其他帖子中使用回调解决方案时遇到的问题,并避免了长时间循环的问题。

使用TypeScript:

这里有一个可以等待的快速sleep()实现。这与上面的答案尽可能相似。它在功能上是等效的,除了ms被键入为TypeScript的数字。

const sleep = (ms: number) =>
  new Promise((resolve) => setTimeout(resolve, ms));

async function demo() {
  console.log('Taking a break for 2s (2000ms)...');
  await sleep(2000);
  console.log('Two seconds later');
}

demo();

就这样。等待睡眠(<持续时间>)。

注意,

await只能在前缀为async关键字的函数中执行,或者在某些环境中在脚本的顶层执行(例如,Chrome DevTools控制台或Runkit)。await只暂停当前的异步函数。

如果确实要暂停脚本,可以执行以下操作:

var milliseconds;
var pretime;
var stage;

function step(time){
  switch(stage){
    case 0:
      //Code before the pause

      pretime=time;
      milliseconds=XXX;
      stage=1;
      break;
    case 1:
      //Code that is looped through while paused

      if(time-pretime >= milliseconds){
        //Code after the pause

        pretime=time;
        milliseconds=XXX;
        stage=2;
      }
      break;
    case 2:
      //Code that is looped through while paused

      if(time-pretime >= milliseconds){
        //Code after the pause

        pretime=time;
        milliseconds=XXX;
        stage=3;
      }
      break;
    case 3:
      //Etc...
  }

  Window.requestAnimationFrame(step)
}

step();

如果您使用循环,这可能正是您想要的,并且您可以以某种方式对其进行更改,从而获得伪多线程,其中一些函数等待一段时间,其他函数正常运行。我一直在纯JavaScript游戏中使用这个。

Use:

等待新的Promise(resol=>setTimeout(resolve,2000));

确保调用函数是异步的。这是经过验证的,工作正常。

在LiveScript(编译为JavaScript)中,可以执行以下操作:

sleep = (ms, func) -> set-timeout func, ms

console.log "hello-1"
<- sleep 2000ms
console.log "hello-2"
<- sleep 2000ms
console.log "hello-3"