Background:
The following code demonstrates that the alert function blocks the operation of setTimeout:
// clock time
function now(){ return (new Date()).getTime() }
var start = now(),
elapsed_before_interruption
// This will interrupt the function below
setTimeout(function(){
elapsed_before_interruption = now()-start
alert('Paused')
start = now()
}, 2000)
setTimeout(function(){
var elapsed_since_interruption = now() - start
var elapsed = elapsed_since_interruption + elapsed_before_interruption
// drop < 1/100s from display
var t = Math.round(100 * elapsed / 1000)/ 100
// Always finishes ~4 seconds after (i.e has been interrupted)
alert( 'Elapsed time: ' + t 's' )
}, 4000)
fiddle
This makes for an excellent pause mechanism when I am choreographing various function calls based upon predetermined intervals.
My question:
Can this be done without calling alert?
EDIT
Whilst similar to the following question: What is the JavaScript version of sleep()? the responses to that question predominantly make the assumption that the OP is dealing with a scheduling issue and suggest code restructuring. I would like to keep this question up as I am specifically not asking for advice on working with promises etc.
By means of explanation, I am writing single web pages (only my code) that are used to conduct timed response latency trials. There are many moving parts and I can implement pause by simply writing
function pause(){ alert('paused') }
I however have to introduce the ugly browser dialog. Anyway to avoid this?
The very short answer: Don't do it this way. If you need to control the order of async processes, there are a variety of better ways.
For debugging, use the Chrome dev tools to set a breakpoint. Much easier.
If you want to wait for something specific, approaches like Promises, callbacks, and libraries like async or queue are relatively easy to use and more flexible.
If you want the syntactical simplicity of waiting in the middle of a function, try precompiling your code with babel and using the async/await syntax, which behaves in a similar way to what you have here (though you need to wait for something specific).
Note that none of these are "true thread blocking". There's only one thread in JS (unless you're using Workers or similar); you can block it with something like while(true) {}, but it locks everything in your browser window, including user interactions. You don't actually want that.
Related
I was testing the accuracy of setTimeout using this test. Now I noticed that (as expected) setTimeout is not very accurate but for most appliances not dramatically inaccurate. Now if I run the test in Chrome and let it run in a background tab (so, switching to another tab and browse on there), returning to the test and inspecting the results (if the test finished) they are dramatically changed. It looks like the timeouts have been running a lot slower. Tested in FF4 or IE9 this didn't occur.
So it looks like Chrome suspends or at least slows down javascript execution in a tab that has no focus. Couldn't find much on the internet on the subject. It would mean that we can't run background tasks, like for example checking periodically on a server using XHR calls and setInterval (I suspect to see the same behavior for setInterval, will write a test if time is with me).
Has anyone encountered this? Would there be a workaround for this suspension/slowing down? Would you call it a bug and should I file it as such?
I recently asked about this and it is behaviour by design. When a tab is inactive, only at a maximum of once per second the function is called. Here is the code change.
Perhaps this will help:
How can I make setInterval also work when a tab is inactive in Chrome?
TL;DR: use Web Workers.
There is a solution to use Web Workers, because they run in separate process and are not slowed down
I've written a tiny script that can be used without changes to your code - it simply overrides functions setTimeout, clearTimeout, setInterval, clearInterval
Just include it before all your code
http://github.com/turuslan/HackTimer
Playing an empty sound forces the browser to retain the performance. I discovered it after reading this comment: How to make JavaScript run at normal speed in Chrome even when tab is not active?
With the source of that comment found here:
The Chromium insider also clarified that aggressive throttling will be automatically disabled for all background tabs “playing audio” as well as for any page where an “active websocket connection is present.”
I need unlimited performance on-demand for a browser game that uses WebSockets, so I know from experience that using WebSockets doesn't ensure unlimited performance, but from tests, playing an audio file seems to ensure it
Here's two empty audio loops I created for this purpose, you can use them freely, commercially:
http://adventure.land/sounds/loops/empty_loop_for_js_performance.ogg
http://adventure.land/sounds/loops/empty_loop_for_js_performance.wav
(They include -58db noise, -60db doesn't work)
I play them, on user-demand, with Howler.js: https://github.com/goldfire/howler.js
function performance_trick()
{
if(sounds.empty) return sounds.empty.play();
sounds.empty = new Howl({
src: ['/sounds/loops/empty_loop_for_js_performance.ogg','/sounds/loops/empty_loop_for_js_performance.wav'],
volume:0.5,
autoplay: true, loop: true,
});
}
It's sad that there is no built-in method to turn full JavaScript performance on/off by default, yet, crypto miners can hijack all your computing threads using Web Workers without any prompt.
I have released worker-interval npm package which setInterval and clearInterval implementation with using Web-Workers to keep up and running on inactive tabs for Chrome, Firefox and IE.
Most of the modern browsers (Chrome, Firefox and IE), intervals (window timers) are clamped to fire no more often than once per second in inactive tabs.
You can find more information on
https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setInterval
https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers#Timeouts_and_intervals
For unit tests you can run your chrome/chromium with argument: --disable-background-timer-throttling
I updated my jQuery core to 1.9.1, and it solved the Interval discrepancy in inactive tabs. I would try that first, then look into other code override options.
here is my solution which gets the current millisecond, and compares it to the millisecond that the function was created. for interval, it will update the millisecond when it runs the function. you can also grab the interval/timeout by an id.
<script>
var nowMillisTimeout = [];
var timeout = [];
var nowMillisInterval = [];
var interval = [];
function getCurrentMillis(){
var d = new Date();
var now = d.getHours()+""+d.getMinutes()+""+d.getSeconds()+""+d.getMilliseconds();
return now;
}
function setAccurateTimeout(callbackfunction, millis, id=0){
nowMillisTimeout[id] = getCurrentMillis();
timeout[id] = setInterval(function(){ var now = getCurrentMillis(); if(now >= (+nowMillisTimeout[id] + +millis)){callbackfunction.call(); clearInterval(timeout[id]);} }, 10);
}
function setAccurateInterval(callbackfunction, millis, id=0){
nowMillisInterval[id] = getCurrentMillis();
interval[id] = setInterval(function(){ var now = getCurrentMillis(); if(now >= (+nowMillisInterval[id] + +millis)){callbackfunction.call(); nowMillisInterval[id] = getCurrentMillis();} }, 10);
}
//usage
setAccurateTimeout(function(){ console.log('test timeout'); }, 1000, 1);
setAccurateInterval(function(){ console.log('test interval'); }, 1000, 1);
</script>
I have developed a music sequencer in javascript; something like this: http://stepseq.michd.me/
I have implemented loop using setInterval function in following way:
var Sequencer = {
...
// every step sequencer ...
next: function(callback) {
// restart from begin if arrive to last sequecer step
if(Sequencer.current==Sequencer.steps.length)
Sequencer.current = 0;
// play all sounds in array step contains
if(Sequencer.steps[Sequencer.current].length>0) {
var set = Sequencer.steps[Sequencer.current];
for(var i=0;i<set.length;i++){
set[i].play();
}
}
callback(Sequencer.current);
Sequencer.current++;
},
loop: function(callback) {
Sequencer.interval = $interval(function(){
Sequencer.next(callback);
}, Sequencer.time);
}
}
...
Code below works but i think that there is a better way to implement loop; infact sometimes steps goes out of time. Sequencer.time (time passed to setInterval function) is a time in millisecs (this value is the conversion of a bpm value; for example it can be 125),
Someone can suggest me a better solution?
N.B.: this is a web application angularjs based (for this reason in code above a use $interval insteed of setInterval), but i think that this point is insignificant.
Javascript timer intervals are not guaranteed to run at exactly the time you request, due to the single threaded nature of JS. What you get is a callback that is queued up to run after the interval expires, whenever the engine is free to run it.
John resig has covered this off in some depth:
http://ejohn.org/blog/how-javascript-timers-work/
http://ejohn.org/blog/analyzing-timer-performance/
And from his conclusions, which is going to be important for your app:
If a timer is blocked from immediately executing it will be delayed
until the next possible point of execution (which will be longer than
the desired delay).
I don't really have a better solution for your problem, due to these fundamental issues with timers in JS, but this may at least explain what is happening.
I am trying to figure out why in my Code section, this.sleep(5000) seems to be getting called before my draw function, because it doesn't get drawn to the canvas until after sleep is done. any insights on why this isn't working the way I want it to?
Sleep function:
sleep: function(milliseconds) {
setTimeout(function(){
var start = new Date().getTime();
while ((new Date().getTime() - start) < milliseconds){
// Do nothing
}
},0);
},
Code:
var g = new Graph(this.diagram);
g.DrawPolygons(ctx,"blue");
this.sleep(5000);
Short answer
Don't do it this way. Even if you get it to work, it will be inconsistent, will cause you many problems, and is almost globally considered bad practice.
Long answer
JavaScript runtimes are almost always designed to be asynchronous. Your while loop is intended to make everything... wait. You cannot (or at least shouldn't) do that in most JavaScript environments.
Instead, schedule events/functions to be executed some number of ms in the future. This is what setTimeout is for. This removes the need for a sleep function.
Here's what your code might look like after the changes described above are applied:
var g = new Graph(this.diagram);
g.DrawPolygons(ctx, "blue");
setTimeout(function() {
g.DrawPolygons(ctx, "red"); // Or whatever
setTimeout(function() {
g.DrawPolygons(ctx, "yellow"); // Or whatever
// etc..
}, 5000);
}, 5000);
ES2015 update - using promises
To avoid potential deeply nested setTimeouts, you can use this
const sleep ms = new Promise(resolve => setTimeout(resolve,ms));
which is simply a promise that resolves in ms milliseconds. This allows you to keep everything in one block:
var g = new Graph(this.diagram);
g.DrawPolygons(ctx, "blue");
(async () => {
g.DrawPolygons(ctx, "red");
await sleep(5000);
g.DrawPolygons(ctx, "yellow");
await sleep(5000);
// ...
})()
Note two things:
Under the hood, there are still events/callback. It looks like C's or Python's sleep but behave very differently.
You can only use this inside asynchronous functions. See here for more information.
There are several problems with the code you've posted. First off, you should never use a while loop to halt code execution.
Secondly, you're setting a timeout, which allows other code to be executed in the interim (yes, even if the timeout is zero seconds). Remove that and you should be able to pause execution (BUT DON'T DO THIS):
sleep: function(milliseconds) {
var start = new Date().getTime();
while ((new Date().getTime() - start) < milliseconds){
// Do nothing
}
},
However, occupying the JS thread means that other browser operations (redraws, etc) will be halted until your sleep function exits. Just having this code in your JS file is an antipattern, you'd be better off finding a different way to solve your problem. Read up on the XY problem and ask a new question.
In case all you wanted to do was execute some code after a certain interval without blocking everything else, setTimeout is all you need.
sleep: function(ms, funcToExecute) {
setTimeout(funcToExecute, ms);
},
(Though at this point, sleep is redundant)
This is happening because of how JavaScript's setTimeout works. When you do:
setTimeout(function(){}, 0)
You are not actually telling it to run the function after 0ms (the lowest value is actually 4ms, but that's besides the point). You are telling it to run the function in the future. What it actually does is put the function at "the end of the stack". It'll finish running the function that called it, and maybe even run some UI redraws before it runs the timeout.
If this code is ran in a loop, your timeouts will not run at all when you think they will ;)
Also, remember JavaScript is single threaded. One thread runs your code as well as the UI redraws. Doing a while loop that does nothing and waits for 5 seconds will lock up the browser. It will prevent any user interaction and UI redraws. It might even make the OS think the browser crashed. DO NOT DO THIS!
Instead, try setting a timeout to run the next polygon after 5000ms:
var g = new Graph(this.diagram);
g.DrawPolygons(ctx,"blue");
setTimeout(function(){
// Code to run after the "sleep"
// Maybe another shape
g.DrawPolygons(ctx, "red");
}, 5000);
The context
We have an Ember-based app which handles large amount of structured data (Business process models).
Important! We would really like to keep our app offline-able, as far as possible.
The need
While we only have to display these data, edit them, and so on, there is no show-stopper in the radar...
But now, we want to apply processing on these models: validity checking, paths finding... and several kind of time/memory consuming algorithms.
The problem
We could process algorithms on the server, but that would kill the app's offline mode.
We have thought about web workers to avoid freezing application and process algorithms in the background, but we faced a major issue: data duplication when passing the data to the worker.
Using Transferable Objects would make the app lose the ownership (and the data) during at least the computation, so it does not seem viable.
How would you handle this problem? Is our only way out the use of a "coroutine-like" implementation of our algorithms? Any clue?
If your major concern is not to freeze UI during lengthy javascript processing you developed, you can refactor loop bodies into sequential steps, such that each step call its next by using window.setTimeout. This technique allows the (single) thread to process UI events between each interaction:
var pr = function(x) {console.log(x)};
var COUNT=3;
// original regular javascript loop
for(var i=0; i<COUNT; i++) {
var msg = "current index is (" + i + ")";
pr(msg);
}
// step-by-step sequential calls
var body = function(i) {
var msg = "non-blocking for: index is (" + i + ")";
pr(msg);
}
nonBlockingFor(body, 4);
The function nonBlockingFor calls the first argument (as a function) the number of times passed as second argument. It's definition follows:
// function constructor
var nonBlockingFor = (function() {
function _run(context) {
if(context.idx > context.max) return;
context.fnc(context.idx++);
window.setTimeout((function(){ _run(context)}), 1);
}
return (function _start(ufn, uqt, runId) {
_run({idx: 0, max: uqt -1, fnc: ufn || (function(){}), runId: runId});
});
})();
Please note that this is a very simplified function and it can be improved to handle other multi-thread related issues -- i.e: waiting for the threads to finish (join). I hope this code helps you. Please let me know if you like this approach to the problem, I could spend some time improving my suggestion, if you like.
Long time has passed, but still : a solution may be http://jscex.info/
Javascript is single threaded in nature, and it's a design choice cause multithreading is a hard topic 99% of the casual javascript developers would not handle properly.
Workers are the only way to obtain another thread and not block the UI, but to make them usable without the dangerous side effects of real multithreading, they run in a completely separated context, as you noticed. So they are more similar to calling an external command passing command line parameters than spawning another thread.
So, working in "async" mode is the only solution right now, but since you are not waiting for a click of a button or a remote connection to complete, the only async event you can bind to is the tick of a timer, which leads to the poor code style that plagues long running operations in js.
There is however a small library, that I found to be very interesting and quite unknown, that (despite it's poor website) is able to "convert" on the fly a beautifully written procedural code to the mess of timers and functions the async model inherently requires : http://jscex.info/
As in windows 3.1, you just need to "yield" ( $await(Jscex.Async.sleep(50)); ) some time to the browser so that it does not completely freeze. It will actually freeze under the hood, but if you yield frequently enough no one will ever notice :) (afterall, that is how multitasking still works inside each single core of your cpu, very small slices of time during which the CPU is 100% working on a single set of instructions .. take that to 20 ms an no one can tell).
I think that could help you "produce" a coroutine-like JS without actually "writing" such code, but delegating to a "precompiler" the work of messing it up.
I would like to thread some Javascript code while both the main process and thread are free to update the browser UI.
For example:
function StartStuff() {
StartThreadedCode();
// do more work and update the UI while StartThreadedCode() does its work
}
function StartThreadedCode() {
// do stuff (do work and update the UI)
}
Is it possible?
There are two main ways to achieve "multithreading" in Javascript. The first way is a cross-browser solution, that would also work in older browsers, but is more complicated to implement.
The idea behind it is that you give the UI some time to update every once in awhile. Since there's no synchronous sleep function in Javascript, the only way to achieve this is to use setTimeout (or setInterval with a little bit more complicate logic) to delay the execution of every loop of your complex calculations. This would give the browser some time to update the UI between loops, giving the visual effect of multiple things happening simultaneously. A few ms should be more than enough for the UI to reflect the latest changes.
It has it's drawbacks of course, and can be quite difficult to implement if there are multiple actions the user might want to do while the background calculations are being performed. Also it can drastically slow down the whole background calculation, since it's delayed a few ms now and then. In specific cases, however, it does the trick and performs well.
The second option would be to use web workers, that are basically Javascript scripts running independently in the background, like a thread. It's much easier to implement, you only have to worry about messaging between main code and background workers, so your whole application isn't affected as much. You can read about using them from the link posted by Mic https://developer.mozilla.org/en/Using_web_workers. The greatest drawback of web workers is their support by browsers, which you can see at http://caniuse.com/#search=worker There's no possible workaround for IE <9 or mobile browsers that truly simulate the effect, so there's not much you can do about those browsers, but then again, the benefits of modern browsers might outweigh poor IE support. This, of course, depends on your application.
Edit: Im not sure whether I explained the first concept clearly enough, so I decided to add a small example. The following code is functionally equivalent to:
for (var counter = 0; counter < 10; counter++) {
console.log(counter);
}
But instead of logging 0-9 in quick succession, it delays 1s before executing the next iteration of the loop.
var counter = 0;
// A single iteration of your calculation function
// log the current value of counter as an example
// then wait before doing the next iteration
function printCounter() {
console.log(counter);
counter++;
if (counter < 10)
setTimeout(printCounter, 1000);
}
// Start the loop
printCounter();
As of 2009 (FF 3.5/Gecko 1.9.1) a new Web API was added that is called Web Workers. It works also on Chrome 4+, Opera 10.6+ and IE10+.
The worker is basically a background thread that runs in a separate process.
The communication between the master process (eg. your UI's main thread) and the slave process (the background thread, the worker) is established with the aid of a generic PostMessage/onmessage function where you can exchange whatever data you like between the two parties.
It is worth mentioning that every single worker is assigned to a different core. For instance by creating 4 different workers (that do a long-running computation) on a quad-processor you are going to see all the 4 CPU-cores like 100% while the main-script is still idling and thus responding to your UI events (look at this example).
A basic example:
main-script.js
if ("function" !== typeof window.Worker) {
throw "Your browser doesn't support Web Workers";
}
var thread = new Worker("background-thread.js");
thread.onmessage = function(e) {
console.log("[A] : I received a " + e.data + " :-P");
};
thread.onerror = function(e) {
console.log(e);
};
console.log("[A] : I'm sending a PING :-)");
thread.postMessage("PING");
background-thread.js
onmessage = function(e) {
console.log("[B] : I receveid a " + e.data + " :-)");
console.log("[B] : I will respond with a PONG ;-)");
postMessage("PONG");
};
The above example should produce the following output at your browser's console:
[A] : I'm sending a PING :-)
[B] : I receveid a PING :-)
[B] : I will respond with a PONG ;-)
[A] : I received a PONG :-P
So happy PING-ing to your background script!
Javascript is single threaded language, but you can do some tricks to imitate multithreading:
http://www.nczonline.net/blog/2009/08/11/timed-array-processing-in-javascript/
http://www.nczonline.net/blog/2011/09/19/script-yielding-with-setimmediate/
http://www.nczonline.net/blog/2011/05/03/better-javascript-animations-with-requestanimationframe/