Everyone’s written a JavaScript loop that just loops over all the {LIs,
links, divs} on a
page\*,
and it’s pretty standard. Something like
var lis = document.getElementsByTagName(“li”);
for (var i=0; i
This is problematic if there are, say, 2000 LI elements on the page, and
what you’re doing in the loop is semi-intensive (imagine you’re creating
a couple of extra elements to append to each of those LIs, or something
like that). The reason this is a problem is that JavaScript is
single-threaded. A tight loop like this hangs the browser until it’s
finished, you get the “this script has been running for a long time”
dialog, and the user interface doesn’t update while you’re in this kind
of loop. You might think: aha, this will take a long time, so I’ll have
some sort of a progress monitor thing:
var lis = document.getElementsByTagName(“li”);
for (var i=0; i
so you move the bit of work you need to do into a function, and that
function re-schedules itself repeatedly, using `setTimeout`. This time,
your user interface will indeed update, and your progress monitor will
show where you’re up to. There are a couple of caveats with this: it’ll
take a bit longer, and you’re no longer guaranteed to have things
processed in the order you expect, but they’re minor issues. For doing
this in jQuery, a tiny plugin:
jQuery.eachCallback = function(arr, process, callback) {
var cnt = 0;
function work() {
var item = arr[cnt];
process.apply(item);
callback.apply(item, [cnt]);
cnt += 1;
if (cnt < arr.length) {
setTimeout(work, 1);
}
}
setTimeout(work, 1);
};
jQuery.fn.eachCallback = function(process, callback) {
var cnt = 0;
var jq = this;
function work() {
var item = jq.get(cnt);
process.apply(item);
callback.apply(item, [cnt]);
cnt += 1;
if (cnt < jq.length) {
setTimeout(work, 1);
}
}
setTimeout(work, 1);
};
and now you can do
$.eachCallback(someArray, function() {
// “this” is the array item, just like $.each
}, function(loopcount) {
// here you get to do some UI updating
// loopcount is how far into the loop you are
});
$(“li”).eachCallback(function() {
// do something to this
}, function(loopcount) {
// update the UI
});
Not always a useful technique, but when you need it, you need it.