There\’s no such thing. Correct me if I\’m wrong, but multi-threading in javascript does not exist. But we can simulate it, as is discussed by James Edwards. How does it work?
It all hinges on the use of asynchronous timers. When we run repetitive code inside an asynchronous timer, we’re giving the browser’s script interpreter time to process each iteration.
This is a solution for those times we have our scripts set up to do some major processing with loops, which causes the browser to hang. In Firefox you get an \”unresponsive script\” warning during those times.
Effectively, a piece of code inside a for iterator is asking the interpreter to do everything straight away: “run this code n times as fast as possible.†However the same code inside an asynchronous timer is breaking the code up into small, discreet chunks; that is, “run this code once as fast possible,â€â€”then wait—then “run this code once as fast as possibleâ€, and so on, n times.
The trick is that the code inside each iteration is small and simple enough for the interpreter to process it completely within the speed of the timer, be it 100 or 5,000 milliseconds. If that requirement is met, then it doesn’t matter how intense the overall code is, because we’re not asking for it to be run all at once.
The Code
function checksomething(){
var okay = false;
var i = 0, limit = 100, busy = false;
var processor = setInterval(function(){
if(!busy){
busy = true;
if(condition){
okay = true;
}
if(++i == limit){
clearInterval(processor);
}
busy = false;
}
}, 100);
}
Notice that in line 4 we\’re setting an interval to run a function every 100ms. Once the iteration has met the limit, it clears the interval. So basically, we have something running in the background every 100ms. This solves the problem of causing the browser to spit out the \”unresponsive script\” warning. But there\’s another problem. If you want the function to return something, it will always return false because:
…the inner function is asynchronous. The outer function will return before the first iteration of the inner function has even happened!
This got me thinking about how I\’ve used callback functions when doing ajax requests. Basically, you pass in a function as an argument and have it run inside the function.
var test_func = function(){
alert(\'this is test func.\');
}
var test_func2 = function(callBack){
alert(\'this is test func 2.\');
callBack();
}
test_func2(test_func);
/* Result is an alert appears stating \"this is test func 2\" and right after another alert appears stating \"this is test func\". */
Upon reading further, James also had the same idea.
function checksomething(oncomplete){
var okay = false;
var i = 0, limit = 100, busy = false;
var processor = setInterval(function(){
if(!busy){
busy = true;
if(condition){
okay = true;
}
if(++i == limit){
clearInterval(processor);
if(typeof oncomplete == \'function\'){
oncomplete(okay);
}
}
busy = false;
}
}, 100);
}
You can also use setTimeout()/clearTimeout() instead of setInterval()/clearInterval().
In MooTools 1.2.1
MooTools has some methods to the timing stuff too. The function periodical() method uses setInterval() and the function delay() method uses setTimeout(). Both can be cleared using $clear() by passing in the timer.
var delay_run = run_func.delay(1000); //runs the function in one second.
var periodical_run = run_func.periodical(1000);//runs the function every one second.
//Clears the timers
$clear(delay_run);
$clear(periodical_run);
Here\’s one of James\’ functions but with the periodical() method:
var count_func = function(callBack){
var i = 0, limit = 20, busy = false;
var processor = (function(){
if(!busy){
busy = true;
if(++i == limit){
$clear(processor);
if($type(callBack) == \'function\'){
callBack();
}
}
busy = false;
}
}).periodical(100);
}
I know it looks pretty much the same. But it\’s just SLIGHTLY cleaner.. yeah? Well the point is that now you know about simulating multi-threading in javascript!
Thank you James for introducing me and everyone else to this technique. This was an awesome lesson!
P.S. Word on the street (or a user comment on James\’ article) is that:
Per the difference between setTimeout and setInterval, as I understand it, they both generate events, which get put on a queue. Since a webpage basically runs in a single thread, only one event can be handled at a time, so the events on the queue just run in order, one after another- including the timers. Thus, the timer never executes EXACTLY in the interval you specify. The timer only generates an event exactly when you specify, and the event function itself only gets executed whenever the browser\’s single thread gets up to it in the queue. One additional consequence is that if a setInterval event happens, and there\’s already a setInterval event on the queue that hasn\’t been executed yet, the new event doesn\’t get added to the queue. So setInterval events get dropped. The smaller you set your interval, and the more complex your function, the more likely they are to get dropped.
this doesn\’t happen with setTimeout however. Since the new setTimeout events don\’t get added until the last setTimeout function has finished, you never have more than one timer event on the queue at a time.
I suggest figuring out a way to use setTimeout to make sure that a timer event isn\’t dropped.
I read that article earlier this week and didn’t really think about it too much because I wasn’t doing anything applicable at the time. But yesterday I was trying to speed up some javascript or at least give the illusion of speeding up some javascript.
I think this might be the trick. I’ll have to try on monday.
@Mike: Thanks for checking this out. Let me know how that ‘speeding up’ works for you?
I know this is an old thread, but it did come up in a search for me today. On the off chance that anyone gets this far, “Web Workers” are a new way to solve the original problem
http://ejohn.org/blog/web-workers/