Javascript IOS5 "JavaScript execution exceeded timeout"

Solution 1:

If you want to execute a long running operation in javascript and you are getting anywhere close to the script execution time limit enforced by some browsers, then you will have to break your function into multiple pieces, run one piece, to a very short setTimeout(fn, 1) and then execute the next piece, etc... Doing it this way, you can run code for hours because it gives other scripts and other events a chance to process. It sometimes requires a minor amount of code restructuring to be able to do this, but it's always possible with a little work.

The basic concept in pseudo-code would be this:

var state = {};   // set initial state
var done = false;

function doWork() {
   // do one increment of work that will never get even close to the browser
   // execution time limit
   // update the state object with our current operating state for the next execution
   // set done = true when we're done processing
   if (!done) {
       setTimeout(doWork, 1);
   }
}

doWork();

In your specific code, you could do something like this. You can process 100 latitude points at a time and then do a short setTimeout to do the next 100 and so on. You can adjust that 100 number to whatever would work best. The higher the number, the more you do on each timer and the better overall execution time, but the closer you get to the browser script execution limit. The setTimeout keeps the browser alive (processing other events) and prevents the execution time limit from kicking in.

function test() {
    var d1 = new Date();
    var lat1, lon1, lat2, lon2, done = false;;
    lat1 = -36;
    lon1 = 174;

    lat2 = lat1;
    lon2 = lon1;

    function calcGC() {
        var cntr = 0;
        while (lat2 > -37 && cntr < 100) {
            lat2 = lat2 - 0.001;
            var stest = "lat1=" + lat1 + ",lon1=" + lon1 + ",lat2=" + lat2 + ",lon2=" + lon2 + "=" + gc(lat1, lon1, lat2, lon2);
            cntr++;
        }
        // if we have more to go, then call it again on a timeout
        if (lat2 > -37) {
            setTimeout(calcGC, 1);
        } else {
            var d2 = new Date();
            var stest = (d2.getTime() - d1.getTime()) / 1000.0 + "s";
            $("#lblTest").html(stest + "<BR/>" + $("#lblTest").html());
        }
    }
    calcGC();
}

Solution 2:

My feeling is that there is a bug in IOS5 safari, because once I've started to get these errors, I get them all over the place (including the Google mobile search page), with no visible timeout/pause occurring. Killing Safari and restarting it fixes the problem (until it happens again - perhaps it's a genuine timeout which puts Safari into the broken state initially).

Have you tried killing Safari via the multitasking menu and restarting it?

Solution 3:

Sounds like Apple reduced the execution timeout for javascript in iOS5. This was probably due to general speed improvements in Mobile Safari and also the inclusion of the Nitro engine for UIWebViews.