Skip to content

Instantly share code, notes, and snippets.

@honmaaax
Forked from ronkorving/ios6-timers.js
Created October 16, 2012 03:08
Show Gist options
  • Select an option

  • Save honmaaax/3897054 to your computer and use it in GitHub Desktop.

Select an option

Save honmaaax/3897054 to your computer and use it in GitHub Desktop.

Revisions

  1. Ron Korving revised this gist Sep 21, 2012. 1 changed file with 61 additions and 34 deletions.
    95 changes: 61 additions & 34 deletions ios6-timers.js
    Original file line number Diff line number Diff line change
    @@ -6,7 +6,7 @@
    // This code is free to use by anyone (MIT, blabla).
    // Author: rkorving@wizcorp.jp

    var timers = {};
    var timeouts = {};
    var intervals = {};
    var orgSetTimeout = window.setTimeout;
    var orgSetInterval = window.setInterval;
    @@ -15,62 +15,80 @@


    function createTimer(set, map, args) {
    var id, cb = args[0];
    var id, cb = args[0], repeat = (set === orgSetInterval);

    function callback() {
    if (cb) {
    delete map[id];
    cb.apply(window, arguments);
    cb = null;

    if (!repeat) {
    delete map[id];
    cb = null;
    }
    }
    }

    args[0] = callback;

    id = set.apply(window, args);

    map[id] = { args: args, created: Date.now(), cb: cb };
    map[id] = { args: args, created: Date.now(), cb: cb, id: id };

    return id;
    }


    function resetTimers(set, clear, oldMap, newMap, correctInterval) {
    for (var id in oldMap) {
    var timer = oldMap[id];
    function resetTimer(set, clear, map, virtualId, correctInterval) {
    var timer = map[virtualId];

    if (!timer) {
    return;
    }

    var repeat = (set === orgSetInterval);

    // cleanup
    // cleanup

    clear(id);
    clear(timer.id);

    // reduce the interval (arg 1 in the args array)
    // reduce the interval (arg 1 in the args array)

    if (!repeat) {
    var interval = timer.args[1];

    if (correctInterval) {
    var reduction = Date.now() - timer.created;
    if (reduction < 0) {
    reduction = 0;
    }
    var reduction = Date.now() - timer.created;
    if (reduction < 0) {
    reduction = 0;
    }

    interval -= reduction;
    if (interval < 0) {
    interval = 0;
    }
    interval -= reduction;
    if (interval < 0) {
    interval = 0;
    }

    timer.args[0] = timer.cb;
    timer.args[1] = interval;
    }

    // recreate
    // recreate

    createTimer(set, newMap, timer.args);
    function callback() {
    if (timer.cb) {
    timer.cb.apply(window, arguments);
    if (!repeat) {
    delete map[virtualId];
    timer.cb = null;
    }
    }
    }

    timer.args[0] = callback;
    timer.created = Date.now();
    timer.id = set.apply(window, timer.args);
    }


    window.setTimeout = function () {
    return createTimer(orgSetTimeout, timers, arguments);
    return createTimer(orgSetTimeout, timeouts, arguments);
    };


    @@ -79,27 +97,36 @@
    };

    window.clearTimeout = function (id) {
    delete timers[id];
    orgClearTimeout(id);
    var timer = timeouts[id];

    if (timer) {
    delete timeouts[id];
    orgClearTimeout(timer.id);
    }
    };

    window.clearInterval = function (id) {
    delete intervals[id];
    orgClearInterval(id);
    var timer = intervals[id];

    if (timer) {
    delete intervals[id];
    orgClearInterval(timer.id);
    }
    };

    window.addEventListener('scroll', function () {
    // recreate the timers using adjusted intervals
    // we cannot know how long the scroll-freeze lasted, so we cannot take that into account

    var oldTimers = timers;
    var oldIntervals = intervals;
    var virtualId;

    timers = {};
    intervals = {};
    for (virtualId in timeouts) {
    resetTimer(orgSetTimeout, orgClearTimeout, timeouts, virtualId);
    }

    resetTimers(orgSetTimeout, orgClearTimeout, oldTimers, timers, true);
    resetTimers(orgSetInterval, orgClearInterval, oldIntervals, intervals, false);
    for (virtualId in intervals) {
    resetTimer(orgSetInterval, orgClearInterval, intervals, virtualId);
    }
    });

    }(window));
  2. Ron Korving created this gist Sep 20, 2012.
    105 changes: 105 additions & 0 deletions ios6-timers.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,105 @@
    (function (window) {

    // This library re-implements setTimeout, setInterval, clearTimeout, clearInterval for iOS6.
    // iOS6 suffers from a bug that kills timers that are created while a page is scrolling.
    // This library fixes that problem by recreating timers after scrolling finishes (with interval correction).
    // This code is free to use by anyone (MIT, blabla).
    // Author: rkorving@wizcorp.jp

    var timers = {};
    var intervals = {};
    var orgSetTimeout = window.setTimeout;
    var orgSetInterval = window.setInterval;
    var orgClearTimeout = window.clearTimeout;
    var orgClearInterval = window.clearInterval;


    function createTimer(set, map, args) {
    var id, cb = args[0];

    function callback() {
    if (cb) {
    delete map[id];
    cb.apply(window, arguments);
    cb = null;
    }
    }

    args[0] = callback;

    id = set.apply(window, args);

    map[id] = { args: args, created: Date.now(), cb: cb };

    return id;
    }


    function resetTimers(set, clear, oldMap, newMap, correctInterval) {
    for (var id in oldMap) {
    var timer = oldMap[id];

    // cleanup

    clear(id);

    // reduce the interval (arg 1 in the args array)

    var interval = timer.args[1];

    if (correctInterval) {
    var reduction = Date.now() - timer.created;
    if (reduction < 0) {
    reduction = 0;
    }

    interval -= reduction;
    if (interval < 0) {
    interval = 0;
    }
    }

    timer.args[0] = timer.cb;
    timer.args[1] = interval;

    // recreate

    createTimer(set, newMap, timer.args);
    }
    }


    window.setTimeout = function () {
    return createTimer(orgSetTimeout, timers, arguments);
    };


    window.setInterval = function () {
    return createTimer(orgSetInterval, intervals, arguments);
    };

    window.clearTimeout = function (id) {
    delete timers[id];
    orgClearTimeout(id);
    };

    window.clearInterval = function (id) {
    delete intervals[id];
    orgClearInterval(id);
    };

    window.addEventListener('scroll', function () {
    // recreate the timers using adjusted intervals
    // we cannot know how long the scroll-freeze lasted, so we cannot take that into account

    var oldTimers = timers;
    var oldIntervals = intervals;

    timers = {};
    intervals = {};

    resetTimers(orgSetTimeout, orgClearTimeout, oldTimers, timers, true);
    resetTimers(orgSetInterval, orgClearInterval, oldIntervals, intervals, false);
    });

    }(window));