In general long loops are not great for running in Javascript, even if they are asynchronous. This is because the threading model is not well specified (this is changing however in the new version being developed) - and consequently there are no guarantees about the semantics of concurrency.
Concurrent
== Two things execute at the same instant in time
Asynchronous
== One thing finishes before the result from a second thing it started running is available.
It's an important distinction. You can have asynchronous execution in current browsers, but there is no guarantee to have concurrency - so your long loop is very likely going to interfere with and block something else that wants to run, even if it's async. That might be some other setTimeout thread of execution, or a render thread, or an event handler...
So what can you do about this?
A very Javascript-centric thing to do, it's very idiomatic - is to subdivide tasks up into asynchronous units that "continue" from one another. You do a unit of work, and the function that implements it receives the next unit of work, or a closure callback to notify when it is finished. So you might do something like:
function loopProcessing(cb) {
var index = 0;
worker = function(cb) {
index += 1;
// Process expensive work unit /index/
if (index >= MAX_INDEX) setTimeout(cb,0);
setTimeout(worker,0,cb);
}
setTimeout(worker,0,cb);
}
loopProcessing(function() { alert("Finished all work!"); });
// This call returns immediately, and other threads of execution
// in the system will never have to wait more than one work unit.
Of course, this isn't the fastest way to crank out those work units - as some commenters pointed out. There is overhead when calling functions. But if what you mean by "slowness" is actually lack of responsiveness in the front-end due to those render / event threads blocking, patterns like this will help you.