14

Yes, I know - that question has thousands of answers. please, don't tell me about setTimeout method because - yes, everything is possible with that but not so easy as using sleep() method.

For example:

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;
}

if you know how to get the same result using setTimeout - tell me ;) fibanacci is pretty easy task, because there aren't more than 2 recursions, but how about n-recursions (like fib(1) + fib(2) + .. + fib(n)) and sleep after every "+"? Nah, sleep would be muuuuuch easier.

But still I can't get working example of implementing it. while (curr - start < time) { curr = (...) } is tricky, but it won't work (just stops my browser and then throw all console logs at once).

franzlorenzon
  • 5,333
  • 6
  • 31
  • 55
Diazath
  • 175
  • 1
  • 1
  • 4

5 Answers5

40

The question is asking how to implement sleep() in JavaScript, right?

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

I just tested it like so:

console.log('hello');
sleep(5000);
console.log('world');

Works for me.

(As a meta comment: I landed here because I have a particular need for this function. Such needs do come up when you need to block while waiting for a value. Even in JavaScript.)

Murph
  • 529
  • 4
  • 3
  • 1
    Nope. Presumably the Q is about synchronous vs asynchronous programming and how to code it asynchronously. I wouldn't understand that myself based on the Q. But it becomes apparent by the asker's comment on the [accepted answer](http://stackoverflow.com/a/4634095/923794). It may be controversial to start answering questions with already accepted answers. But, of course, that's a case-by-case thing, and may be beneficial. Askers may change the accepted answers later. – cfi Jul 08 '13 at 17:53
  • 1
    Coding a synchronous `sleep()` that just burns cpu cycles rarely makes sense. In most operating systems, even if you do it like this, you cannot prevent that control will be taken from your process. In fact, for exactly this reason actively looping and polling the time is less accurate than to release control to the system and ask it to wake you up at a certain time (=event). Maybe there's a use case in a real time OS or on a non-preemptable privilege level... – cfi Jul 08 '13 at 17:56
  • 2
    On the other hand, a synchronous `sleep()` can be very useful, e.g. to test some esoteric `setInterval()/clearInterval()` behavior in the presence of a possible (but not yet present) very long-running JS task. This is the only answer that answers the question "How do I sleep() in JS". Not that I think this is the answer most people want, but that's because most people asking for `sleep()` don't actually want `sleep()`. – user508633 Jan 06 '15 at 06:55
  • I know this practice is bad. But sometimes you just need it. Thanks for doing the hard work for us @Murph – Pubudu Dodangoda Sep 18 '19 at 07:35
20

I dont fully understand what you're asking, but I'm going to answer this part:

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

The fundamental difference is that sleep (as used in many other languages) is synchronous, while setTimeout (and many other JavaScript-concepts, like AJAX for example) are asynchronous. So, in order to rewrite your function we have to take this into account. Mainly, we have to use a callback to fetch the "return value", rather than an actual return-statement, so it will be used like this:

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

So, as for the implementation:

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

I would also like to point out that, no, this is not an easier solution than using sleep. Why? Because this code is asynchronous and that's simply more complicated than synchronous code for what most people are used to. It takes practice to start thinking in that way.

The upside? It allows you to write non-blocking algorithms that outperforms their synchronous counterparts. If you haven't heard of Node.js before, you could check it out to further understand the benefits of this. (Many other languages have libraries for dealing with async IO as well, but as long as were talking about JavaScript..)

Jakob
  • 23,205
  • 7
  • 44
  • 55
  • 1
    So as i see i have no other option than start thinging that way. Thanks. – Diazath Jan 08 '11 at 14:01
  • 1
    @Diazath: Yeah, that's pretty much it. You won't regret it though, it frees your mind ;) – Jakob Jan 08 '11 at 14:09
  • solid answer Jakob, it's taking me longer than I'd like to grok asynchronous programming (callbacks, context/closures) but I'm getting there after many years of c/c++ coding. – Mark Essel Jun 14 '12 at 19:26
3

The trouble with a sleep() type function within a browser (or any other GUI environment for that matter) is that it is an event-driven environment, and wouldn't be able to sleep() in the way you're describing it.

The setTimeout() method works because it is creating an event, and setting the trigger for that event to be a point in time. Therefore the system can give over control of the waiting to the event handler and Javascript itself is free to carry on doing other things.

In the web browser, virtually everything works this way. Mouse click/hover/etc functions are event triggers. Ajax requests don't sit and wait for the response from the server; they set an event to trigger when the response is received.

Time based actions are also done with event triggers, using functions like setTimeout().

This is how it's done. In fact this is how it's done in pretty much any well-written GUI application, because all GUI interfaces must be able to respond to events such as mouse clicks virtually instantly.

A Javascript sleep() function (especially the way it's been implemented in another answer here!) would basically have the effect burn up your CPU cycles while it waited for the clock. The sleep() would remain the active process, meaning that other events may not be processed straight away - which means your browser would appear to stop responding to mouse clicks, etc for the duration of the sleep. Not a good thing.

setTimeout() is the way to go. There is always a way to do it; the resulting code may not be neat and linear like your example code, but event-driven code very rarely is linear - it can't be. The solution is to break the process down into small functions. you can even embed the subsequent functions inside the setTimeout() call, which may go some way to helping you keep your code at least having some appearance of being linear.

Hope that helps explain things a bit for you.

Spudley
  • 157,081
  • 38
  • 222
  • 293
  • 2
    Everything you say is true for Javascript *in an asynchronous environment.* There's nothing about JavaScript as a programming language that insists on asynchronous runtime behavior. In fact most server-side Javascript environments are synchronous; Rhino is a good example. – Pointy Jan 08 '11 at 13:43
  • @Pointy - thanks; I've modified the answer to emphasize the fact that we're talking specifically about the browser environment. – Spudley Jan 08 '11 at 13:50
  • 1
    @Pointy And then there's the "oh so awesome" Node.js which is completely asynchronous (yes there are a few special sync methods for reading files but those are for config purposes). But yes, in general there's nothing special about JS, in fact, Node implement setTimeout etc. itself :) – Ivo Wetzel Jan 08 '11 at 13:56
2

Just use a better algorithm without loops or recursion, and avoid the need for setTimeout() / sleep().

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

Usage example:

// Log the first 10 Fibonacci numbers (F0 to F9) to the console
for (var i = 0; i < 10; i++) {
  console.log(fibonacci(i));
}
Mathias Bynens
  • 130,201
  • 49
  • 208
  • 240
  • 1
    He's not asking for a better algorithm to calculate the actual sequence. For some reason he wants to sleep (maybe to prove the point that his algorithm is VERY slow for non-tiny N). I won't downvote though, since the question is so very poorly expressed. – Jakob Jan 08 '11 at 13:44
  • @Jakob: I realize that. I had actually posted a different answer before, explaining that implementing `sleep()` is a bad idea but that it could be done, and got buried in downvotes *because* it’s a bad idea. Oh well, it’s now removed. – Mathias Bynens Jan 08 '11 at 13:47
  • 1
    Haha, I see. Pearls for swine I suppose :) (no offence people who are not used to async code, but you're missing something) – Jakob Jan 08 '11 at 13:50
0

Why on earth do you want to 'sleep' while computing anything? Sleeping for any time is nearly always a bad idea in any language. It essentially tells the thread to stop doing anything for that period of time.

So, in a language like javascript that only has one thread (forgetting 'web workers'), what benefit would you reap for pausing ALL computation? It's a bad idea, forget it.

Now to the problem that you've written, though I don't think this is your actual problem. Why do you want to pause for a second while computing this sequence? Even to compute the first 6 numbers in the sequence, it's going to take 8 or so seconds. Why? What possible reason is there to pause for a second between recursive calls? Stop it. Remove it.

If you want to just yield the final result a second after it completes, then use setTimeout with a function uses the answer in some way.

function fib(n) {
    ...
    result = fib();
    ...
    setTimeout(function() {
        console.log("Fib for " + n + " is " + result);
    },1000);
}

Do not try to implement 'sleep'. Do not pause during computation.

Josh Smeaton
  • 43,953
  • 24
  • 121
  • 160
  • 5
    Maybe he's setting up the algorithm for some pedagogical purpose, so between computation steps a "sleep()" is desired. In other words, perhaps the sleeping is done for the purposes of some illustrative animation on a web page. – Pointy Jan 08 '11 at 13:44
  • @Pointy - that's exactly what i'm doing. – Diazath Jan 08 '11 at 13:50
  • 1
    But nothing is being done with the answer.. it runs, sleeps, runs, sleeps, runs, sleeps.. then finally produces an answer at the end. Perhaps the question could have been asked a little better - and this little bit of context supplied. – Josh Smeaton Jan 08 '11 at 13:56
  • also in some context (like for example payment) the user expects it too be slow, and will contact support if the payment is done "too fast" ! so you want to artificially slow things done ... – allan.simon Jan 29 '21 at 12:57