views:

574

answers:

5

Suppose I want to block Javascript execution for certain time for some weird reason, how can I do that. There is no sleep() in JS. Pls don't say do a while() loop because that's bad. I can do a window.showModalDialog and put a window.close in the modal dialog with setTimeout of very small time so that the user doesn't notice the dialog. This will be like sleep for small time period and I can call this multiple time if needed. Is there some other way?

To elaborate, my use case is that HTML5 SQL Database has given async api's but I want to use it for a samll webapp for which the store will never be big. So there is no need of an async api because the queries on the small store will run on the client side. So I want to write an ORM with sync api so that developers can use it more easily. To bridge this async to sync api, I need something like sleep.

+12  A: 

window.setTimeout or window.setInterval are pretty much your only friends.

An example of how to use setTimeout to recursively call a function that sets another timeout is as follows

function go() {
    if (go.count < 4) {
        // logs 1, 2, 3 to firebug console at 1 second intervals
        console.log(go.count++);
        window.setTimeout(go, 1000);
    }
}
go.count = 1;

go();

You may choose to capture the timeoutID to use with window.clearTimeout if you need to clear the timeout prior to it finishing.

Note that neither window.setTimeout nor window.setInterval block execution of other script - I don't believe that this is possible with JavaScript in it's current guise. There are ways that could be coded to mimic UI blocking, such as using showModalDialog or having some global blocking boolean which are about as near as you can get I'm afraid.

Russ Cam
This is already in the question :)
Nick Craver
-1: It's already in the question. And WHO upvoted this?
Vuntic
true, it is in the question but it is pretty much the JavaScript answer to `Thread.Sleep()`/`Insert language equivalent`.
Russ Cam
@Russ - Fair enough, and not my downvote, see my profile ;) but your answer should explain this a bit more.
Nick Craver
I up-voted it. Just because its in the question doesn't mean it's not the answer. This answer says "are pretty much your only friends", which gives more data about what can be used and introduces a new function.
Kerry
I think there may be some confusion about how `setTimeout` works, and that may be why the OP mentioned `setTimeout`, but didn't realize it was the solution.
pkaeding
This won't work. setTimeout does not prevent other code from running. It just postpones the execution and allows the rest of the script to continue.
Techpriester
I never said that they blocked execution of other script, only that they're a way of introducing a delay. I'll make this clearer in the answer
Russ Cam
With setTimeout I will have to work with callbacks which makes the code obscured and difficult to maintain. If my use case permits, I would like to use blocking calls, the paradigm to which developers are more used to.
nomind
@nomind It *is* the way to do it in Javascript, because Javascript is all about callbacks and passing functions around. "Blocking" is *not* how you do it in Javascript, since that blocks **the whole browser**, not just your script. Adopt the development techniques of the language, don't squeeze the language into what you know. Javascript is *not* a procedural language.
deceze
+5  A: 

@Russ Cam is correct, setTimeout is what you are looking for. The way you mentioned it in the question, though, makes me think that there might be some confusion about how it is used.

It will not block execution of the block it is in, rather, it will call its input function after a certain interval. As an illustration:

function illustration() {
  // start out doing some setup code
  alert("This part will run first");

  // set up some code to be executed later, in 5 seconds (5000 milliseconds):
  setTimeout(function () {
    alert("This code will run last, after a 5 second delay")
  }, 5000);

  // This code will run after the timeout is set, but before its supplied function runs:
  alert("This will be the second of 3 alert messages to display");
}

You will see three alert messages when you run this function, with a delay between the second and third:

  1. "This part will run first"
  2. "This will be the second of 3 alert messages to display"
  3. "This code will run last, after a 5 second delay"
pkaeding
Yes I understand that but I want to block the execution so, setTimeout doesn't help out.
nomind
If you want to block execution, then `while` is what you want, but this will freeze the browser (because it is blocking execution). I doubt you really want to block execution.
pkaeding
+3  A: 

This answer may be a bit annoying but bare with it :-).

Since javascript is typically run inside a browser, which is multi-threaded of which javascript may occupying several threads, there is no concept of a "global sleep" the way you would have in a singly threaded program.

If you want to pause an operation in any reasonable way you may want to consider the following.

Let's say you want to the following

function foo(s) {
    var j = 1; var k = 1;
    sleep(s); // This would be nice right?  
    window.alert("Sum is : " + (j+k));
}

Actually becomes:

function foo(s) {
     var j = 1 ; var k = 1;
     setTimeout(s, function() { 
            window.alert("Sum is : " + (j+k));
     });
}

Of course the problem is that in a procedural sense you may want to have something like

function foo() {
   do stuff;
   pause();
   do more stuff;
   return;
}

function bar() {
      foo(10);
      window.alert("I want this to happen only after foo()");
}

The problem is that you can't really do that using setTimeout, as shown above

However you can do something like:

 function foo(s, afterwards, afterparms) {
     var j = 1 ; var k = 1;
     setTimeout(s, function() { 
            window.alert("Sum is : " + (j+k));
            afterparms.parm1 = afterparms.parm1.toUpperCase();
            afterwards(afterparms);
     });
 }

 function bar() {
      foo(10, function() {
          window.alert("This will happen after window.alert");
      }, { parm1: 'hello', parm2: 'world' } );
 }

Please note that above is only ONE way to go about passing information to functions, you can do some really cool stuff if you look up function calling conventions, variable arguments and such

This is annoying to program if you think procedurally. However, there are two things to remember regarding javascript. It is NOT a procedural language, NOR is it an object oriented language. Javascript is a functional language with a sophisticated event management model. So you have to think in those terms.

It makes sense too, since the typical javascript machine is a gui (web browser) which by design do not want to completely block while trying to process something. Imagine your browser completely locking up while a page is doing something, you'd want to strangle the programmer who does that to you.

Javascript code should be of 'fire-and-forget' nature, and if things have to wait for an event to occur before proceeding then you should be looking at the javascript event model.

While this is inconvenient programming when you want to do something trivial, chances are you are using pause to wait in a way which may run into race conditions to begin with, and that there is a more appropriate way to go about the "effect" that you are attempting to achieve.

If you post your PARTICULAR case, there may be more information forthcoming as to how one may address such a situation.

Cheers,

Elf King
Wrong. JS does NOT run multithreaded. setTimeout also does not do what the question asks for. See my answer for details.
Techpriester
JavaScript IS single-threaded. And so are many browsers.
el.pescado
I appreciate all your comments. I have updated the question with my use case, if that justifies the need of sleep().
nomind
I disagree with your comment that JavaScript is neither Object Oriented nor Procedural - See http://stackoverflow.com/questions/107464/is-javascript-object-oriented. Did you mean it does not have class based implementation inheritance?
Russ Cam
+2  A: 

I can do a window.showModalDialog and put a window.close in the modal dialog with setTimeout of very small time

That's inventive, but it only allows for user interaction with anything in the modal dialog, for the length of time it's open. The rest of the browser remains hung as surely as if you'd just called a brutal while (new Date().getTime()<t1); loop.

The modal dialog is kinder on CPU cycles and will avoid triggering the script-execution-time watchdog in the case of longer waits, but you'd have to balance that against the annoyance of a distracting flashing-open dialog box, and the non-universal browser support, and the issue of everyone hating modal dialogs!

This will be like sleep for small time period and I can call this multiple time if needed. Is there some other way?

What are you actually trying to achieve by sleeping? Without returning to the event loop or firing a modal dialog, you're not going to get any on-screen update or user interaction, so I don't see what an inline sleep is going to do for you. You certainly can't do animation this way.

In Firefox you get Python-style generators, which would allow you to write a procedural-style interaction process using yield to return control to the browser as necessary. This can improve the simplicity of code as you don't have to re-write conditional and looping structures as remembered state in variables. However as only Mozilla browsers support it you can't really use it in the wild for the foreseeable future.

ETA:

I want to write an ORM with sync api so that developers can use it more easily. To bridge this async to sync api, I need something like sleep.

Sorry, can't be done in the general case. Basic JavaScript does not have threads, co-routines or other primitives that can bridge sync and async code.

The Web SQL Database spec relies on browsers invoking your result-handling function (passed to executeSql()) as a browser callback. Browser callbacks can only fire when control has passed back to the browser, not inside a synchronous thread of execution.

In theory, you could open a modalDialog, do the asynchronous Web SQL Database call inside the modalDialog's window, and have the modalDialog return the result to synchronous code in the caller window's scripts. However, there is currently no browser that supports both openDatabase and openModalDialog!

bobince
See the use case in the updated question, if that justifies the need. But there are problems with my showModalDialog approach like even if I close it say within 10ms, it might show up on slow machines (is this possible?) and the focus not coming back to the correct place in the parent window.
nomind
@nomind: Added unhelpful info. Maybe if future browsers implement both modal dialogues and SQL together it could be feasible, but as well as the problems of flashing up the window, it would require users to disable their pop-up blockers. I think you're going to have to live with asynchronous code and callback functions. Or just use the more widely-supported synchronous `localStorage` backend instead of exotic `openDatabase`: for a ‘small webapp’ with object-style access, the characteristics of a relational database won't help you at all.
bobince
I disagree. Any webkit based browser like google chrome has both showModalDialog and openDatabase
nomind
+3  A: 

To clarify: The question is to halt the script execution completely for a certain amount of time, not to delay the execution of some piece of code, which wouild be a task for setTimeout or setInterval.

A clean implementation of sleep() is just not possible and also not desireable in JavaScript.

setTimout and setInterval do NOT halt the script execution like some people here seem top think. The just register a function to be run postponed. The rest of the script will continue running while the timeout/interval is waiting.

Due to the asynchronous nature of JavaScript, the only way to "block" any code execution would the very ugly and ABSOLUTELY NOT RECOMMENDED while loop that runs for a given amount of time. Since JavaScript itself runs in one single thread (we're not talking about WebWorkers API here ...). This would stop any JS code from being run until that loop finishes. But thats really bad style ...

If your program can not work without something like sleep(), maybe you should rethink your approach.

Techpriester