可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
This question already has an answer here:
-
What is the JavaScript version of sleep()?
70 answers
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.
回答1:
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.
回答2:
@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:
- "This part will run first"
- "This will be the second of 3 alert messages to display"
- "This code will run last, after a 5 second delay"
回答3:
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.
回答4:
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,
回答5:
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
!
回答6:
I know this question is a bit old, but I had a similar issue where I needed to simulate a script that took a long time to load on the page. I ended up solving the problem by creating a server side endpoint that waited 5 seconds before sending the response then added a script tag to the DOM to point to this.
Granted it requires a server side implementation, however, it allows you to stop the page at any specific point. As others have said before, this will block the whole browser, not just your script.