Difference between revisions of "Useful functions"
From SoundDB
(Created page with "<pre> 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 setTimeou...") |
|||
(2 intermediate revisions by the same user not shown) | |||
Line 41: | Line 41: | ||
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. | 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. | ||
+ | |||
+ | </pre> | ||
+ | |||
+ | <pre> | ||
+ | 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(); | ||
+ | </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> | ||
+ | <!DOCTYPE HTML> | ||
+ | <html> | ||
+ | <head> | ||
+ | <meta http-equiv="Content-type" content="text/html;charset=UTF-8"> | ||
+ | <title>Show File Data</title> | ||
+ | <style type='text/css'> | ||
+ | body { | ||
+ | font-family: sans-serif; | ||
+ | } | ||
+ | </style> | ||
+ | <script type='text/javascript'> | ||
+ | |||
+ | function loadFile() { | ||
+ | var input, file, fr; | ||
+ | |||
+ | if (typeof window.FileReader !== 'function') { | ||
+ | bodyAppend("p", "The file API isn't supported on this browser yet."); | ||
+ | return; | ||
+ | } | ||
+ | |||
+ | input = document.getElementById('fileinput'); | ||
+ | if (!input) { | ||
+ | bodyAppend("p", "Um, couldn't find the fileinput element."); | ||
+ | } | ||
+ | else if (!input.files) { | ||
+ | bodyAppend("p", "This browser doesn't seem to support the `files` property of file inputs."); | ||
+ | } | ||
+ | else if (!input.files[0]) { | ||
+ | bodyAppend("p", "Please select a file before clicking 'Load'"); | ||
+ | } | ||
+ | else { | ||
+ | file = input.files[0]; | ||
+ | fr = new FileReader(); | ||
+ | fr.onload = receivedText; | ||
+ | fr.readAsText(file); | ||
+ | } | ||
+ | |||
+ | function receivedText() { | ||
+ | showResult(fr, "Text"); | ||
+ | |||
+ | fr = new FileReader(); | ||
+ | fr.onload = receivedBinary; | ||
+ | fr.readAsBinaryString(file); | ||
+ | } | ||
+ | |||
+ | function receivedBinary() { | ||
+ | showResult(fr, "Binary"); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function showResult(fr, label) { | ||
+ | var markup, result, n, aByte, byteStr; | ||
+ | |||
+ | markup = []; | ||
+ | result = fr.result; | ||
+ | for (n = 0; n < result.length; ++n) { | ||
+ | aByte = result.charCodeAt(n); | ||
+ | byteStr = aByte.toString(16); | ||
+ | if (byteStr.length < 2) { | ||
+ | byteStr = "0" + byteStr; | ||
+ | } | ||
+ | markup.push(byteStr); | ||
+ | } | ||
+ | bodyAppend("p", label + " (" + result.length + "):"); | ||
+ | bodyAppend("pre", markup.join(" ")); | ||
+ | } | ||
+ | |||
+ | function bodyAppend(tagName, innerHTML) { | ||
+ | var elm; | ||
+ | |||
+ | elm = document.createElement(tagName); | ||
+ | elm.innerHTML = innerHTML; | ||
+ | document.body.appendChild(elm); | ||
+ | } | ||
+ | |||
+ | </script> | ||
+ | </head> | ||
+ | <body> | ||
+ | <form action='#' onsubmit="return false;"> | ||
+ | <input type='file' id='fileinput'> | ||
+ | <input type='button' id='btnLoad' value='Load' onclick='loadFile();'> | ||
+ | </form> | ||
+ | </body> | ||
+ | </html> | ||
</pre> | </pre> |
Latest revision as of 12:50, 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) })
<!DOCTYPE HTML> <html> <head> <meta http-equiv="Content-type" content="text/html;charset=UTF-8"> <title>Show File Data</title> <style type='text/css'> body { font-family: sans-serif; } </style> <script type='text/javascript'> function loadFile() { var input, file, fr; if (typeof window.FileReader !== 'function') { bodyAppend("p", "The file API isn't supported on this browser yet."); return; } input = document.getElementById('fileinput'); if (!input) { bodyAppend("p", "Um, couldn't find the fileinput element."); } else if (!input.files) { bodyAppend("p", "This browser doesn't seem to support the `files` property of file inputs."); } else if (!input.files[0]) { bodyAppend("p", "Please select a file before clicking 'Load'"); } else { file = input.files[0]; fr = new FileReader(); fr.onload = receivedText; fr.readAsText(file); } function receivedText() { showResult(fr, "Text"); fr = new FileReader(); fr.onload = receivedBinary; fr.readAsBinaryString(file); } function receivedBinary() { showResult(fr, "Binary"); } } function showResult(fr, label) { var markup, result, n, aByte, byteStr; markup = []; result = fr.result; for (n = 0; n < result.length; ++n) { aByte = result.charCodeAt(n); byteStr = aByte.toString(16); if (byteStr.length < 2) { byteStr = "0" + byteStr; } markup.push(byteStr); } bodyAppend("p", label + " (" + result.length + "):"); bodyAppend("pre", markup.join(" ")); } function bodyAppend(tagName, innerHTML) { var elm; elm = document.createElement(tagName); elm.innerHTML = innerHTML; document.body.appendChild(elm); } </script> </head> <body> <form action='#' onsubmit="return false;"> <input type='file' id='fileinput'> <input type='button' id='btnLoad' value='Load' onclick='loadFile();'> </form> </body> </html>