JavaScript睡眠

JavaScript sleep

本问题已经有最佳答案,请猛点这里访问。

是的,我知道-那个问题有成千上万的答案。请不要告诉我关于setTimeout方法的事,因为-是的,用它一切都是可能的,但不像使用sleep()方法那么容易。

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function fibonacci(n) {
    console.log("Computing Fibonacci for" + n +"...");
    var result = 0;

    //wait 1 second before computing for lower n
    sleep(1000);
    result = (n <= 1) ? 1 : (fibonacci(n - 1) + fibonacci(n - 2));

    //wait 1 second before announcing the result
    sleep(1000);
    console.log("F(" + n +") =" + result);

    return result;
}

如果你知道如何使用setTimeout得到相同的结果,告诉我;)fibanacci是一项非常简单的任务,因为没有超过2个递归,但是n个递归(如fib(1)+fib(2)+.+每次"+"后睡一觉?不,睡眠会更容易。

但我还是找不到实施它的有效例子。while (curr - start < time) { curr = (...) }很棘手,但它不起作用(只需停止浏览器,然后立即抛出所有控制台日志)。


问题是如何在javascript中实现sleep(),对吗?

1
2
3
4
5
function sleep(ms) {
  var start = new Date().getTime(), expire = start + ms;
  while (new Date().getTime() < expire) { }
  return;
}

我只是这样测试它:

1
2
3
console.log('hello');
sleep(5000);
console.log('world');

为我工作。

(作为元注释:我在这里登陆是因为我特别需要这个函数。当您在等待值时需要阻塞时,就会出现这种需求。即使是在javascript中。)


我不完全理解你的要求,但我会回答这部分:

if you know how to get the same result
using setTimeout - tell me

基本的区别是,sleep(在许多其他语言中使用)是同步的,而setTimeout(以及许多其他的javascript概念,例如Ajax)是异步的。所以,为了重写函数,我们必须考虑到这一点。主要的,我们必须使用回调来获取"返回值",而不是实际的返回语句,因此它的使用方式如下:

1
2
3
fibonacci(7, function(result) {
  // use the result here..
});

因此,在实施方面:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
function fibonacci(n, callback) {
  console.log("Computing Fibonacci for" + n +"...");
  var result = 0;

  var announceAndReturn = function() {
    setTimeout(function() {
      // wait 1 second before announcing the result
      console.log("F(" + n +") =" + result);
      callback(result); //"returns" the value
    }, 1000);
  };

  // wait 1 second before computing lower n
  setTimeout(function() {
    if (n <= 1) {
      result = 1;
      announceAndReturn();
    }
    else {
      var resultsLeft = 2;

      var handler = function(returned) {
        result += returned;
        resultsLeft--;
        if (resultLeft == 0)
          announceAndReturn();
      }

      fibonacci(n-1, handler);
      fibonacci(n-2, handler);
    }
  }, 1000);
}

我还想指出,不,这并不是比使用sleep更容易的解决方案。为什么?因为这段代码是异步的,对于大多数人来说,这比同步代码要复杂得多。以这种方式开始思考需要实践。

有利的一面?它允许您编写性能优于同步算法的非阻塞算法。如果您以前没有听说过node.js,您可以查看它来进一步了解它的好处。(许多其他语言也有处理异步IO的库,但只要谈论的是JavaScript….)


在浏览器(或任何其他GUI环境)中,sleep()类型函数的问题在于它是一个事件驱动的环境,不能像您描述的那样使用sleep()

setTimeout()方法之所以有效,是因为它正在创建一个事件,并将该事件的触发器设置为一个时间点。因此,系统可以将等待的控制权交给事件处理程序,而javascript本身可以自由地进行其他操作。

在Web浏览器中,几乎所有东西都是这样工作的。鼠标点击/悬停/etc函数是事件触发器。Ajax请求不会等待服务器的响应;它们会设置一个事件,在收到响应时触发。

基于时间的操作也可以使用事件触发器,使用诸如setTimeout()之类的函数。

就是这样做的。事实上,这是在几乎所有编写良好的GUI应用程序中都可以做到的,因为所有的GUI接口都必须能够对事件(如鼠标单击)做出即时响应。

一个javascript sleep()函数(特别是在另一个答案中实现它的方式!)基本上会有这样的效果:在等待时钟的时候,烧掉你的CPU周期。sleep()将保持活动进程,这意味着其他事件可能不会立即处理,这意味着您的浏览器在睡眠期间似乎停止响应鼠标单击等。不是好事。

江户一〔3〕是前进的道路。总是有一种方法可以做到这一点;产生的代码可能不像示例代码那样整洁和线性,但是事件驱动代码很少是线性的——它不可能是线性的。解决方案是将流程分解为小函数。甚至可以将后续函数嵌入到setTimeout()调用中,这可能有助于保持代码至少具有某种线性外观。

希望能帮你解释一下。


只需使用一个没有循环或递归的更好的算法,并避免需要setTimeout()/sleep()

1
2
3
function fibonacci(n) {
  return Math.round(Math.pow((Math.sqrt(5) + 1) / 2, Math.abs(n)) / Math.sqrt(5)) * (n < 0 && n % 2 ? -1 : 1);
}

使用实例:

1
2
3
4
// Log the first 10 Fibonacci numbers (F0 to F9) to the console
for (var i = 0; i < 10; i++) {
  console.log(fibonacci(i));
}


你到底为什么要在计算任何东西的时候"睡觉"?在任何语言中,睡觉几乎总是一个坏主意。它本质上告诉线程在这段时间内停止做任何事情。

所以,在一种只有一个线程的语言(忘记"web workers")中,暂停所有计算会有什么好处?这是个坏主意,算了吧。

现在谈谈你写的问题,尽管我不认为这是你真正的问题。在计算这个序列时,为什么要暂停一秒钟?即使要计算序列中的前6个数字,也需要8秒左右的时间。为什么?在递归调用之间暂停一秒钟的可能原因是什么?住手。除去它。

如果您只想在完成后一秒钟生成最终结果,那么在函数中使用setTimeout会以某种方式使用答案。

1
2
3
4
5
6
7
8
function fib(n) {
    ...
    result = fib();
    ...
    setTimeout(function() {
        console.log("Fib for" + n +" is" + result);
    },1000);
}

不要试图实现"睡眠"。不要在计算过程中暂停。