Difference between revisions of "Useful functions"

From SoundDB
Jump to: navigation, search
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)
})