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/
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 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>
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.
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 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>