EDIT: per Yogi's comment (see "setTimeout" and "throttling" in https://developer.mozilla.org/en-US/docs/Web/API/setTimeout ), I've tried adding an AudioContext to prevent the slowdown.
document.addEventListener('click', ev => {
let audCtxt = new AudioContext({});
});
(AudioContext needs user interaction, hence the event listener.)
But, no luck.
Other ideas I'm noting here to follow up are
maybe a while loop, checking Date.now() for multiples of 10ms -- but I think that would crash the page
maybe using requestAnimationFrame?
Original post:
I have a setTimeout firing every 0.01 seconds that's acting as a master clock for my web app.
The app plays synchronized sounds that respond to user interaction, hence the need for a master clock. Simplified:
let counter = 0;
setTimeout(() => {
counter++;
console.log(counter);
}, 10);
When on a mobile device, the setTimeout slows down (about 2-4x) when the screen is locked/off. (Tested on Android, not iOS).
This can be verified by logging, like the above, or by generating a sound when the counter is multiple of 100.
How can I prevent this?
Should I be taking a different approach to a "master clock" that synchronizes triggering audio samples while still allowing the audio to respond in real time to user interaction?
setTimeout is not reliable as other things, such as promises, have higher execution priority. One possible workaround is to create a custom timer using promises. Here is an example:
var customDelay = new Promise(function (resolve) {
var delay = 10; // milliseconds
var before = Date.now();
while (Date.now() < before + delay) { };
resolve();
});
customDelay.then(function () {
//Timer triggered
});
Update 1:
Given that you want a 10ms update frequency, running the above code on the main thread ends up locking up the UI due to the while loop. With that in mind, offloading that while loop into a web worker would resolve this. Here is some code:
<html>
<head>
<title></title>
</head>
<body>
<script id="FastTimer" type="javascript/worker">
onmessage = function (event) {
var delay = 10; // milliseconds
var before = Date.now();
while (Date.now() < before + delay) { };
postMessage({data: []});
};
</script>
<script>
var worker;
window.onload = function() {
var blob = new Blob([document.querySelector("#FastTimer").textContent]);
blobURL = window.URL.createObjectURL(blob);
worker = new Worker(blobURL);
worker.addEventListener("message", receivedWorkerMessage);
worker.onerror = workerError;
//Start the worker.
worker.postMessage({});
}
var counter = 0;
function receivedWorkerMessage(event) {
worker.postMessage({});
timerTiggered();
}
function timerTiggered() {
counter++;
console.log(counter);
}
function workerError(error) {
alert(error.message);
}
function stopWorker() {
worker.terminate();
worker = null;
}
</script>
</body>
</html>
The main issue with the above is that I suspect there would be some sort of time cost going back and forth between the worker (maybe a couple ms, hard to say).
As mentioned, normally requestAnimationFrame is used for animations in web apps. However, this would likely not fire when the screen is locked. But if you want to try, here is a sample:
<html>
<head>
<title></title>
</head>
<body>
<script>
var counter = 0;
var minTimeSpan = 10;
var lastTime = performance.now();
function animate() {
let t = performance.now();
if (t - lastTime >= minTimeSpan) {
timerTiggered();
}
requestAnimationFrame(animate);
}
function timerTiggered() {
counter++;
console.log(counter);
}
animate();
</script>
</body>
</html>
This can usually be solved by using a Web Worker for running the timer. I created a library which looks like setTimeout() but uses a Web Worker internally.
https://github.com/chrisguttandin/worker-timers
But there was a bug a while ago in some browser (I forgot which one it was) which caused this to not work any longer. Therefore I built the same abstraction on top of a running AudioContext.
https://github.com/chrisguttandin/audio-context-timers
But as you already said this only works if the page is already allowed to run an AudioContext by starting one in response to a click handler.
I've got a bunch of integration tests using headless chrome. Because restarting the browser on an entirely new profile is so expensive the harness tries to "clean up" the browser state (flush caches, clear cookies and storage, ...) on teardown.
However there's a recurring issue that during the cleanup phase some async operations resolve and try to do whatever they do in a now nonsensical state.
There are two issues here:
async stack traces support in CDT are listed as experimental and don't appear at all in the response (possibly because they have to be enabled via a hidden flag somehow)
I have no idea what's still running at that point, and can't really even debug what breaks due to (1)
Is there any way to improve the situation expect by trawling through heisenbugs as they occur, trying to slowly make my way up the async callstacks throuth ever more logging until the root cause is found?
First we make a hook to be able to capture all xhr packets. You'll have to execute this before any of your other scripts load. Probaly put this in your boot/prepare script before running tests.
I have implemented below a start and stop button. start makes 300 xhr requests, just the "normal" way. If you press stop, you can cancel them all. Ideally you'd put the stop event handler code in an beforeunload event.
If you don't want to stop them, you can analyze their state, requested urls, etc... from one neat array where you keep track of everything within code.
This example works because only "so" many requests can be made at the same time by the browser. The rest in the queue waits as pending until a slot comes free. I used a 300 requests because I don't know a large/slow source to request from that isn't CORS protected, and this gives us humans enough time to press the stop button(I hope).
function addXMLRequestCallback(callback){
var oldSend, i;
if( XMLHttpRequest.callbacks ) {
// we've already overridden send() so just add the callback
XMLHttpRequest.callbacks.push( callback );
} else {
// create a callback queue
XMLHttpRequest.callbacks = [callback];
// store the native send()
oldSend = XMLHttpRequest.prototype.send;
// override the native send()
XMLHttpRequest.prototype.send = function(){
// process the callback queue
// the xhr instance is passed into each callback but seems pretty useless
// you can't tell what its destination is or call abort() without an error
// so only really good for logging that a request has happened
// I could be wrong, I hope so...
// EDIT: I suppose you could override the onreadystatechange handler though
for( i = 0; i < XMLHttpRequest.callbacks.length; i++ ) {
XMLHttpRequest.callbacks[i]( this );
}
// call the native send()
oldSend.apply(this, arguments);
}
}
}
/**
* adding some debug data to the XHR objects. Note, don't depend on this,
* this is against good practises, ideally you'll have your own wrapper
* to deal with xhr objects and meta data.
* The same way you can extend the XHR object to catch post data etc...
*/
var xhrProto = XMLHttpRequest.prototype,
origOpen = xhrProto.open;
origSend = xhrProto.send;
xhrProto.open = function (method, url) {
this._url = url;
return origOpen.apply(this, arguments);
};
xhrProto.send = function (data) {
this._data = data;
return origSend.apply(this, arguments);
};
+function() {
var xhrs = [],
i,
statuscount = 0,
status = document.getElementById('status'),
DONE = 4;;
addXMLRequestCallback((xhr) => {
xhrs.push(xhr);
});
document.getElementById('start').addEventListener('click',(e) => {
statuscount = 0;
var data = JSON.stringify({
'user': 'person',
'pwd': 'password',
'organization': 'place',
'requiredkey': 'key'
});
for(var i = 0;i < 300; i++) {
var oReq = new XMLHttpRequest();
oReq.addEventListener("load", (e) => {
statuscount++;
status.value=statuscount;
});
oReq.open("GET", 'https://code.jquery.com/jquery-3.4.1.js');
oReq.send(data);
}
});
document.getElementById('cancel').addEventListener('click', (event) => {
for(i = 0; i < xhrs.length; i++) {
if(xhrs[i].readyState !== DONE) {
console.log(xhrs[i]._url, xhrs[i]._data , 'is not done');
}
}
/** Cancel everything */
for(i = 0; i < xhrs.length; i++) {
if(xhrs[i]) {
xhrs[i].abort();
}
}
});
}();
<button id="start">start requests</button>
<button id="cancel">cancel requests</button>
<progress id="status" value="0" max="300"></progress>
Code of addXMLRequestCallback courtesy of meouw from this answer
Code of xhrProto keeping debug variables courtesy Joel Richard of from this answer
I'm trying to understand this example:
HTML (main code):
<html>
<title>Test threads fibonacci</title>
<body>
<div id="result"></div>
<script language="javascript">
var worker = new Worker("fibonacci.js");
worker.onmessage = function(event) {
document.getElementById("result").textContent = event.data;
dump("Got: " + event.data + "\n");
};
worker.onerror = function(error) {
dump("Worker error: " + error.message + "\n");
throw error;
};
worker.postMessage("5");
</script>
</body>
</html>
Javascript (worker code):
var results = [];
function resultReceiver(event) {
results.push(parseInt(event.data));
if (results.length == 2) {
postMessage(results[0] + results[1]);
}
}
function errorReceiver(event) {
throw event.data;
}
onmessage = function(event) {
var n = parseInt(event.data);
if (n == 0 || n == 1) {
postMessage(n);
return;
}
for (var i = 1; i <= 2; i++) {
var worker = new Worker("fibonacci.js");
worker.onmessage = resultReceiver;
worker.onerror = errorReceiver;
worker.postMessage(n - i);
}
};
I have the following questions:
When exactly the worker code starts to run ? Immediately after the execution of var worker = new Worker("fibonacci.js"); ?
Is that true that onmessage = function(event) { ... } assignment in the worker code will be executed before worker.postMessage("5"); in the main code ?
Can worker code access global variables that are defined in the main code (like worker)?
Can main code access global variables that are defined in the worker code (like results)?
It seems to me that worker.onmessage = function(event) {...} in the main code has the same meaning like onmessage = function(event) {...} in the worker code (which is onmessage event handler of the worker). Where am I wrong ? What is the difference between them ?
What this code should actually do ? When I run it here it just prints "5". Is that what it is supposed to do, or I'm missing something ?
Thanks a lot !
Check out HTML5 Rocks: The Basics of Web Workers for general tutorial.
Workers will start as soon as you call the postMessage method of the worker.
the function bound to worker's onmessage in the main code will work when the worker calls postMessage.
global variables are not shared between main and worker threads. The only way to pass data is through messaging via postMessage.
as you suspected, the onmessage on both worker and main code has the same meaning. It is an event handler for when the thread receives a message event. You can even use addEventListener instead, catching message event:
Main Code:
function showResult(event) {
document.getElementById("result").textContent = event.data;
dump("Got: " + event.data + "\n");
}
var worker = new Worker("fibonacci.js");
worker.addEventListener('message', showResult, false);
Worker code:
addEventListener('message', resultReceiver, false);
The fibonacci example you took is a recursive worker example. If not using workers, it would be something like this:
function fibonacci(n) {
if (n == 0 || n == 1) return n;
return fibonacci(n-1) + fibonacci(n-2);
}
var result = fibonacci(5);
dump("Got: " + result + "\n");
(oh no, I'm not going to do a stackless for you. You write it yourself!)
I also want to add that you can debug web workers only in Chromium based browsers. You have to select Sources in developer panel and in right column expand bottom line Workers and then choose check box pause on start.
I can return a value if I send a sync message:
// frame script
var chromeBtnText = sendSyncMessage("getChromeToolbarButtonText");
if (chromeBtnText == 'blah') {
alert('tool is blah');
}
// chrome script
messageManager.addMessageListener("getChromeToolbarButtonText", listener);
function listener(message) {
return document.getElementById('myChromeToolbarButton').label.value;
}
How do I achieve this with a callback with sendAsyncMessage?
I was hoping to do something like:
// frame script
function myCallback(val) {
var chromeBtnText = val;
if (chromeBtnText == 'blah') {
alert('tool is blah');
}
}
var chromeBtnText = sendAsyncMessage("getChromeToolbarButtonText", null, myCallback);
There is no callback for replies. In fact, there is no reply at all. The return value from the chrome message listener is simply ignored for async messages.
To do fully async communication, you'd have to send another message containing the reply.
Frame script
addMessageListener("getChromeToolbarButtonTextReply", function(message) {
alert(message.data.btnText);
});
sendAsyncMessage("getChromeToolbarButtonText");
Chrome
messageManager.addMessageListener("getChromeToolbarButtonText", function(message) {
var btnText = document.getElementById('myChromeToolbarButton').label.value;
// Only send message to the frame script/message manager
// that actually asked for it.
message.target.messageManager.sendAsyncMessage(
"getChromeToolbarButtonTextReply",
{btnText: btnText}
);
});
PS: All messages share a namespace. So to avoid conflicts when another piece of code wants to use the same name getChromeToolbarButtonText, you better choose a more unique name in the first place, like prefixing your messages with your add-on name my-unique-addoon:getChromeToolbarButtonText or something like that. ;)
I was also hoping to do something similar:
messageManager.sendAsyncMessage("my-addon-framescript-message", null, myCallback);
I'm going the other direction so the myCallback would be in chrome but it's exactly the same principle.
I'd used similar approaches to #Noitidart and #nmaier before but in this new case I wanted to bind to some local data so myCallback can behave differently based on the application state at the time the first message was sent rather than at the time the callback is executed, all while allowing for the possibility of multiple message round-trips being in progress concurrently.
Chrome:
let someLocalState = { "hello": "world" };
let callbackName = "my-addon-somethingUnique"; // based on current state or maybe generate a UUID
let myCallback = function(message) {
messageManager.removeMessageListener(callbackName, myCallback);
//message.data.foo == "bar"
//someLocalState.hello == "world"
}.bind(this); // .bind(this) is optional but useful if the local state is attached to the current object
messageManager.addMessageListener(callbackName, myCallback);
messageManager.sendAsyncMessage("my-addon-framescript-message", { callbackName: callbackName } );
Framescript:
let messageHandler = function(message) {
let responseData = { foo: "bar" };
sendAsyncMessage(message.data.callbackName, responseData);
};
addMessageListener("my-addon-framescript-message", messageHandler);
There's a real-world example here: https://github.com/luckyrat/KeeFox/commit/c50f99033d2d07068140438816f8cc5e5e290da9
It should be possible for Firefox to be improved to encapsulate this functionality in the built-in messageManager one day but in the mean-time this approach works well and with a surprisingly small amount of boiler-plate code.
in this snippet below. i add the callback before sendAsyncMessage('my-addon-id#jetpack:getChromeToolbarbuttonText'... as i know it will send back. Then I remove it after callback executes. I know I don't have to but just to kind of make it act like real callback, just to kind of show people, maybe it helps someone understand.
Frame:
/////// frame script
function CALLBACK_getChromeToolbarButtonText(val) {
removeMessageListner('my-addon-id#jetpack:getChromeToolbarButtonTextCallbackMessage', CALLBACK_getChromeToolbarButtonText); //remove the callback
var chromeBtnText = val;
if (chromeBtnText == 'blah') {
alert('tool is blah');
}
}
addMessageListener('my-addon-id#jetpack:getChromeToolbarButtonTextCallbackMessage', CALLBACK_getChromeToolbarButtonText); //add the callback
var chromeBtnText = sendAsyncMessage("my-addon-id#jetpack:getChromeToolbarButtonText", null);
Chrome:
////// chrome script
messageManager.addMessageListener("my-addon-id#jetpack:getChromeToolbarButtonText", listener);
function listener() {
var val = document.getElementById('myChromeToolbarButton').label.value;
sendAsyncMessage('my-addon-id#jetpack:getChromeToolbarButtonTextCallbackMessage',val);
}
Is there some way to do multi-threading in JavaScript?
See http://caniuse.com/#search=worker for the most up-to-date support info.
The following was the state of support circa 2009.
The words you want to google for are JavaScript Worker Threads
Apart from from Gears there's nothing available right now, but there's plenty of talk about how to implement this so I guess watch this question as the answer will no doubt change in future.
Here's the relevant documentation for Gears: WorkerPool API
WHATWG has a Draft Recommendation for worker threads: Web Workers
And there's also Mozilla’s DOM Worker Threads
Update: June 2009, current state of browser support for JavaScript threads
Firefox 3.5 has web workers. Some demos of web workers, if you want to see them in action:
Simulated Annealing ("Try it" link)
Space Invaders (link at end of post)
MoonBat JavaScript Benchmark (first link)
The Gears plugin can also be installed in Firefox.
Safari 4, and the WebKit nightlies have worker threads:
JavaScript Ray Tracer
Chrome has Gears baked in, so it can do threads, although it requires a confirmation prompt from the user (and it uses a different API to web workers, although it will work in any browser with the Gears plugin installed):
Google Gears WorkerPool Demo (not a good example as it runs too fast to test in Chrome and Firefox, although IE runs it slow enough to see it blocking interaction)
IE8 and IE9 can only do threads with the Gears plugin installed
Different way to do multi-threading and Asynchronous in JavaScript
Before HTML5 JavaScript only allowed the execution of one thread per page.
There was some hacky way to simulate an asynchronous execution with Yield, setTimeout(), setInterval(), XMLHttpRequest or event handlers (see the end of this post for an example with yield and setTimeout()).
But with HTML5 we can now use Worker Threads to parallelize the execution of functions. Here is an example of use.
Real multi-threading
Multi-threading: JavaScript Worker Threads
HTML5 introduced Web Worker Threads (see: browsers compatibilities)
Note: IE9 and earlier versions do not support it.
These worker threads are JavaScript threads that run in background without affecting the performance of the page. For more information about Web Worker read the documentation or this tutorial.
Here is a simple example with 3 Web Worker threads that count to MAX_VALUE and show the current computed value in our page:
//As a worker normally take another JavaScript file to execute we convert the function in an URL: http://stackoverflow.com/a/16799132/2576706
function getScriptPath(foo){ return window.URL.createObjectURL(new Blob([foo.toString().match(/^\s*function\s*\(\s*\)\s*\{(([\s\S](?!\}$))*[\s\S])/)[1]],{type:'text/javascript'})); }
var MAX_VALUE = 10000;
/*
* Here are the workers
*/
//Worker 1
var worker1 = new Worker(getScriptPath(function(){
self.addEventListener('message', function(e) {
var value = 0;
while(value <= e.data){
self.postMessage(value);
value++;
}
}, false);
}));
//We add a listener to the worker to get the response and show it in the page
worker1.addEventListener('message', function(e) {
document.getElementById("result1").innerHTML = e.data;
}, false);
//Worker 2
var worker2 = new Worker(getScriptPath(function(){
self.addEventListener('message', function(e) {
var value = 0;
while(value <= e.data){
self.postMessage(value);
value++;
}
}, false);
}));
worker2.addEventListener('message', function(e) {
document.getElementById("result2").innerHTML = e.data;
}, false);
//Worker 3
var worker3 = new Worker(getScriptPath(function(){
self.addEventListener('message', function(e) {
var value = 0;
while(value <= e.data){
self.postMessage(value);
value++;
}
}, false);
}));
worker3.addEventListener('message', function(e) {
document.getElementById("result3").innerHTML = e.data;
}, false);
// Start and send data to our worker.
worker1.postMessage(MAX_VALUE);
worker2.postMessage(MAX_VALUE);
worker3.postMessage(MAX_VALUE);
<div id="result1"></div>
<div id="result2"></div>
<div id="result3"></div>
We can see that the three threads are executed in concurrency and print their current value in the page. They don't freeze the page because they are executed in the background with separated threads.
Multi-threading: with multiple iframes
Another way to achieve this is to use multiple iframes, each one will execute a thread. We can give the iframe some parameters by the URL and the iframe can communicate with his parent in order to get the result and print it back (the iframe must be in the same domain).
This example doesn't work in all browsers! iframes usually run in the same thread/process as the main page (but Firefox and Chromium seem to handle it differently).
Since the code snippet does not support multiple HTML files, I will just provide the different codes here:
index.html:
//The 3 iframes containing the code (take the thread id in param)
<iframe id="threadFrame1" src="thread.html?id=1"></iframe>
<iframe id="threadFrame2" src="thread.html?id=2"></iframe>
<iframe id="threadFrame3" src="thread.html?id=3"></iframe>
//Divs that shows the result
<div id="result1"></div>
<div id="result2"></div>
<div id="result3"></div>
<script>
//This function is called by each iframe
function threadResult(threadId, result) {
document.getElementById("result" + threadId).innerHTML = result;
}
</script>
thread.html:
//Get the parameters in the URL: http://stackoverflow.com/a/1099670/2576706
function getQueryParams(paramName) {
var qs = document.location.search.split('+').join(' ');
var params = {}, tokens, re = /[?&]?([^=]+)=([^&]*)/g;
while (tokens = re.exec(qs)) {
params[decodeURIComponent(tokens[1])] = decodeURIComponent(tokens[2]);
}
return params[paramName];
}
//The thread code (get the id from the URL, we can pass other parameters as needed)
var MAX_VALUE = 100000;
(function thread() {
var threadId = getQueryParams('id');
for(var i=0; i<MAX_VALUE; i++){
parent.threadResult(threadId, i);
}
})();
Simulate multi-threading
Single-thread: emulate JavaScript concurrency with setTimeout()
The 'naive' way would be to execute the function setTimeout() one after the other like this:
setTimeout(function(){ /* Some tasks */ }, 0);
setTimeout(function(){ /* Some tasks */ }, 0);
[...]
But this method does not work because each task will be executed one after the other.
We can simulate asynchronous execution by calling the function recursively like this:
var MAX_VALUE = 10000;
function thread1(value, maxValue){
var me = this;
document.getElementById("result1").innerHTML = value;
value++;
//Continue execution
if(value<=maxValue)
setTimeout(function () { me.thread1(value, maxValue); }, 0);
}
function thread2(value, maxValue){
var me = this;
document.getElementById("result2").innerHTML = value;
value++;
if(value<=maxValue)
setTimeout(function () { me.thread2(value, maxValue); }, 0);
}
function thread3(value, maxValue){
var me = this;
document.getElementById("result3").innerHTML = value;
value++;
if(value<=maxValue)
setTimeout(function () { me.thread3(value, maxValue); }, 0);
}
thread1(0, MAX_VALUE);
thread2(0, MAX_VALUE);
thread3(0, MAX_VALUE);
<div id="result1"></div>
<div id="result2"></div>
<div id="result3"></div>
As you can see this second method is very slow and freezes the browser because it uses the main thread to execute the functions.
Single-thread: emulate JavaScript concurrency with yield
Yield is a new feature in ECMAScript 6, it only works on the oldest version of Firefox and Chrome (in Chrome you need to enable Experimental JavaScript appearing in chrome://flags/#enable-javascript-harmony).
The yield keyword causes generator function execution to pause and the value of the expression following the yield keyword is returned to the generator's caller. It can be thought of as a generator-based version of the return keyword.
A generator allows you to suspend execution of a function and resume it later. A generator can be used to schedule your functions with a technique called trampolining.
Here is the example:
var MAX_VALUE = 10000;
Scheduler = {
_tasks: [],
add: function(func){
this._tasks.push(func);
},
start: function(){
var tasks = this._tasks;
var length = tasks.length;
while(length>0){
for(var i=0; i<length; i++){
var res = tasks[i].next();
if(res.done){
tasks.splice(i, 1);
length--;
i--;
}
}
}
}
}
function* updateUI(threadID, maxValue) {
var value = 0;
while(value<=maxValue){
yield document.getElementById("result" + threadID).innerHTML = value;
value++;
}
}
Scheduler.add(updateUI(1, MAX_VALUE));
Scheduler.add(updateUI(2, MAX_VALUE));
Scheduler.add(updateUI(3, MAX_VALUE));
Scheduler.start()
<div id="result1"></div>
<div id="result2"></div>
<div id="result3"></div>
With the HTML5 "side-specs" no need to hack javascript anymore with setTimeout(), setInterval(), etc.
HTML5 & Friends introduces the javascript Web Workers specification. It is an API for running scripts asynchronously and independently.
Links to the specification and a tutorial.
There's no true threading in JavaScript. JavaScript being the malleable language that it is, does allow you to emulate some of it. Here is an example I came across the other day.
There is no true multi-threading in Javascript, but you can get asynchronous behavior using setTimeout() and asynchronous AJAX requests.
What exactly are you trying to accomplish?
Here is just a way to simulate multi-threading in Javascript
Now I am going to create 3 threads which will calculate numbers addition, numbers can be divided with 13 and numbers can be divided with 3 till 10000000000. And these 3 functions are not able to run in same time as what Concurrency means. But I will show you a trick that will make these functions run recursively in the same time : jsFiddle
This code belongs to me.
Body Part
<div class="div1">
<input type="button" value="start/stop" onclick="_thread1.control ? _thread1.stop() : _thread1.start();" /><span>Counting summation of numbers till 10000000000</span> = <span id="1">0</span>
</div>
<div class="div2">
<input type="button" value="start/stop" onclick="_thread2.control ? _thread2.stop() : _thread2.start();" /><span>Counting numbers can be divided with 13 till 10000000000</span> = <span id="2">0</span>
</div>
<div class="div3">
<input type="button" value="start/stop" onclick="_thread3.control ? _thread3.stop() : _thread3.start();" /><span>Counting numbers can be divided with 3 till 10000000000</span> = <span id="3">0</span>
</div>
Javascript Part
var _thread1 = {//This is my thread as object
control: false,//this is my control that will be used for start stop
value: 0, //stores my result
current: 0, //stores current number
func: function () { //this is my func that will run
if (this.control) { // checking for control to run
if (this.current < 10000000000) {
this.value += this.current;
document.getElementById("1").innerHTML = this.value;
this.current++;
}
}
setTimeout(function () { // And here is the trick! setTimeout is a king that will help us simulate threading in javascript
_thread1.func(); //You cannot use this.func() just try to call with your object name
}, 0);
},
start: function () {
this.control = true; //start function
},
stop: function () {
this.control = false; //stop function
},
init: function () {
setTimeout(function () {
_thread1.func(); // the first call of our thread
}, 0)
}
};
var _thread2 = {
control: false,
value: 0,
current: 0,
func: function () {
if (this.control) {
if (this.current % 13 == 0) {
this.value++;
}
this.current++;
document.getElementById("2").innerHTML = this.value;
}
setTimeout(function () {
_thread2.func();
}, 0);
},
start: function () {
this.control = true;
},
stop: function () {
this.control = false;
},
init: function () {
setTimeout(function () {
_thread2.func();
}, 0)
}
};
var _thread3 = {
control: false,
value: 0,
current: 0,
func: function () {
if (this.control) {
if (this.current % 3 == 0) {
this.value++;
}
this.current++;
document.getElementById("3").innerHTML = this.value;
}
setTimeout(function () {
_thread3.func();
}, 0);
},
start: function () {
this.control = true;
},
stop: function () {
this.control = false;
},
init: function () {
setTimeout(function () {
_thread3.func();
}, 0)
}
};
_thread1.init();
_thread2.init();
_thread3.init();
I hope this way will be helpful.
You could use Narrative JavaScript, a compiler that will transforms your code into a state machine, effectively allowing you to emulate threading. It does so by adding a "yielding" operator (notated as '->') to the language that allows you to write asynchronous code in a single, linear code block.
The new v8 engine which should come out today supports it (i think)
In raw Javascript, the best that you can do is using the few asynchronous calls (xmlhttprequest), but that's not really threading and very limited. Google Gears adds a number of APIs to the browser, some of which can be used for threading support.
If you can't or don't want to use any AJAX stuff, use an iframe or ten! ;) You can have processes running in iframes in parallel with the master page without worrying about cross browser comparable issues or syntax issues with dot net AJAX etc, and you can call the master page's JavaScript (including the JavaScript that it has imported) from an iframe.
E.g, in a parent iframe, to call egFunction() in the parent document once the iframe content has loaded (that's the asynchronous part)
parent.egFunction();
Dynamically generate the iframes too so the main html code is free from them if you want.
Another possible method is using an javascript interpreter in the javascript environment.
By creating multiple interpreters and controlling their execution from the main thread, you can simulate multi-threading with each thread running in its own environment.
The approach is somewhat similar to web workers, but you give the interpreter access to the browser global environment.
I made a small project to demonstrate this.
A more detailed explanation in this blog post.
Javascript doesn't have threads, but we do have workers.
Workers may be a good choice if you don't need shared objects.
Most browser implementations will actually spread workers across all cores allowing you to utilize all cores. You can see a demo of this here.
I have developed a library called task.js that makes this very easy to do.
task.js Simplified interface for getting CPU intensive code to run on all cores (node.js, and web)
A example would be
function blocking (exampleArgument) {
// block thread
}
// turn blocking pure function into a worker task
const blockingAsync = task.wrap(blocking);
// run task on a autoscaling worker pool
blockingAsync('exampleArgumentValue').then(result => {
// do something with result
});
With HTML5 specification you do not need to write too much JS for the same or find some hacks.
One of the feature introduced in HTML5 is Web Workers which is JavaScript running in the background,independently of other scripts, without affecting the performance of the page.
It is supported in almost all browsers :
Chrome - 4.0+
IE - 10.0+
Mozilla - 3.5+
Safari - 4.0+
Opera - 11.5+
Topaz is lock free Multithreaded Javascript Engine for .NET: https://github.com/koculu/topaz