-
-
Save ronkorving/3755461 to your computer and use it in GitHub Desktop.
| (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 released in the public domain. Do with it what you want, without limitations. I do not promise | |
| // that it works, or that I will provide support (don't sue me). | |
| // Author: rkorving@wizcorp.jp | |
| var timeouts = {}; | |
| 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], repeat = (set === orgSetInterval); | |
| function callback() { | |
| if (cb) { | |
| cb.apply(window, arguments); | |
| if (!repeat) { | |
| delete map[id]; | |
| cb = null; | |
| } | |
| } | |
| } | |
| args[0] = callback; | |
| id = set.apply(window, args); | |
| map[id] = { args: args, created: Date.now(), cb: cb, id: id }; | |
| return id; | |
| } | |
| function resetTimer(set, clear, map, virtualId, correctInterval) { | |
| var timer = map[virtualId]; | |
| if (!timer) { | |
| return; | |
| } | |
| var repeat = (set === orgSetInterval); | |
| // cleanup | |
| clear(timer.id); | |
| // reduce the interval (arg 1 in the args array) | |
| if (!repeat) { | |
| var interval = timer.args[1]; | |
| var reduction = Date.now() - timer.created; | |
| if (reduction < 0) { | |
| reduction = 0; | |
| } | |
| interval -= reduction; | |
| if (interval < 0) { | |
| interval = 0; | |
| } | |
| timer.args[1] = interval; | |
| } | |
| // recreate | |
| 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, timeouts, arguments); | |
| }; | |
| window.setInterval = function () { | |
| return createTimer(orgSetInterval, intervals, arguments); | |
| }; | |
| window.clearTimeout = function (id) { | |
| var timer = timeouts[id]; | |
| if (timer) { | |
| delete timeouts[id]; | |
| orgClearTimeout(timer.id); | |
| } | |
| }; | |
| window.clearInterval = function (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 virtualId; | |
| for (virtualId in timeouts) { | |
| resetTimer(orgSetTimeout, orgClearTimeout, timeouts, virtualId); | |
| } | |
| for (virtualId in intervals) { | |
| resetTimer(orgSetInterval, orgClearInterval, intervals, virtualId); | |
| } | |
| }); | |
| }(window)); |
Can anyone confirm is this problem has been resolved in iOS6.1?
I've tried it on iOS6.1, and it seems that the problem has gone away!
Hi.. I have added the fix.js in my header and issue seems to be fixed. But my images are inside a link (anchor tag), while clicking the image, its not redirecting. Just showing the loading icon and nothing happens after that. Please, need help on this :(
You don't need to track timers and intervals separately. You can pass interval IDs to clearTimeout, and the numbers will never overlap, since they use the same underlying list. http://www.whatwg.org/specs/web-apps/current-work/#dom-windowtimers-settimeout
novocaine: requestAnimationFrame isn't a great workaround, since it'll force a much longer delay for small timers (up to 16ms extra).
I wonder what the timing overhead of using a worker comes out to. The onscreen keyboard opening/closing inside a UIWebView (not in Safari) can also cause this issue.
@zewt I figured it wasn't required, but I also didn't want to introduce new cross-browser issues while trying to resolve one. Played it safe there. If all known browsers play nice with this, I guess that could be unified.
Although the bug is fixed in iOS 6.1, is anyone willing to document it on https://github.com/scottjehl/Device-Bugs for posterity? @pixelscript, can yours Radar issue description be used as Device Bugs issue description?
not work for me ;(
I was getting cb.apply is not a function error. It's because native setTimeout allows you to pass a String, which gets eval'd when the timeout expires. This code doesn't handle that case. I had to make this change to function callback():
if (cb) {
if ("string" == typeof cb) {
if ("()" == cb.substring(cb.length - 2, cb.length)) {
cb = cb.substring(0, cb.length - 2)
}
cb = eval(cb);
}
cb.apply(window, arguments);
// etc.
this cods for some reason broke Hammer.js press event, in case any one has the same problem...
also a newer solution in here
http://stackoverflow.com/questions/12855123/ios-6-js-events-function-not-called-if-has-settimeout-in-it