Difference between revisions of "Useful functions"
From SoundDB
					
										
					
					| Line 43: | Line 43: | ||
| </pre> | </pre> | ||
| − | |||
| <pre> | <pre> | ||
| Line 65: | Line 64: | ||
| //start the calculation   | //start the calculation   | ||
| pump();   | pump();   | ||
| + | </pre> | ||
| + | |||
| + | <pre> | ||
| + | arr.sort(function(e1,e2) { | ||
| + |     return e1>e2 ? 1:(e1<e2 ? -1:0) | ||
| + | }) | ||
| + | |||
| + | arr.sort(function(e1,e2) { | ||
| + |     return e1>e2 ? -1:(e1<e2 ? 1:0) | ||
| + | }) | ||
| </pre> | </pre> | ||
Revision as of 12:48, 25 May 2011
setTimeout with a shorter delay
Wednesday, 2010-03-09, 13:45 -0800
On Sunday, somebody with the nickname {g} was on irc.mozilla.org asking about the behavior of setTimeout. In particular, he wanted to divide up work into a bunch of pieces in a way that allowed the user to interact with the page while the work was happening, and was doing this by doing a piece of the work, and then making a setTimeout call to continue the work. (In some cases, this could also be done using workers.) Unfortunately for him, setTimeout in most browsers doesn't allow a delay less than about 10 milliseconds (it forces any smaller delays to be longer), so the work wasn't finishing as fast as it could. (Chrome has changed this to 2 milliseconds, though, and apparently had some problems with it.)
A while ago, Jeff Walden suggested to me that Web pages could get the equivalent of setTimeout, with a real zero delay, using postMessage. This turns out to be relatively straightforward:
    // Only add setZeroTimeout to the window object, and hide everything
    // else in a closure.
    (function() {
        var timeouts = [];
        var messageName = "zero-timeout-message";
        // Like setTimeout, but only takes a function argument.  There's
        // no time argument (always zero) and no arguments (you have to
        // use a closure).
        function setZeroTimeout(fn) {
            timeouts.push(fn);
            window.postMessage(messageName, "*");
        }
        function handleMessage(event) {
            if (event.source == window && event.data == messageName) {
                event.stopPropagation();
                if (timeouts.length > 0) {
                    var fn = timeouts.shift();
                    fn();
                }
            }
        }
        window.addEventListener("message", handleMessage, true);
        // Add the one thing we want added to the window object.
        window.setZeroTimeout = setZeroTimeout;
    })();
I wrote a demo page that demonstrates that this is significantly faster than setTimeout(0). On a Firefox nightly 100 iterations of setZeroTimeout take about 10-20 milliseconds most of the time, but occasionally longer; on a WebKit build I have it takes about 4-6 milliseconds, but occasionally a bit longer. (We should probably investigate the performance difference here.) In comparison, in Firefox and on non-Chromium-based WebKit, the setTimeout version takes about a second (though perhaps even longer on Windows).
Update (2010-03-12): My numbers were on Linux. Boris tells me that on Mac, it's the opposite: Gecko is faster than Safari or Chrome.
function doCalculation() 
{ 
   //do your thing for a short time 
   //figure out how complete you are 
   var percent_complete=.... 
   return percent_complete; 
} 
function pump() 
{ 
   var percent_complete=doCalculation(); 
   //maybe update a progress meter here! 
   //carry on pumping? 
   if (percent_complete<100) 
   { 
      setTimeout(pump, 50); 
   } 
} 
//start the calculation 
pump(); 
arr.sort(function(e1,e2) {
    return e1>e2 ? 1:(e1<e2 ? -1:0)
})
arr.sort(function(e1,e2) {
    return e1>e2 ? -1:(e1<e2 ? 1:0)
})
