Skip to content

Instantly share code, notes, and snippets.

@malcolmocean
Last active April 28, 2017 14:40
Show Gist options
  • Save malcolmocean/567380c149129a93541ffc015c6e63ac to your computer and use it in GitHub Desktop.
Save malcolmocean/567380c149129a93541ffc015c6e63ac to your computer and use it in GitHub Desktop.
Angular Worker-based Interval (to avoid Chrome background tab throttling)
var timers = {}
function fireInterval(id) {
this.postMessage({id: id})
}
var commands = {
setInterval: function W_setInterval(data) {
var time = parseInt(data.time || 0, 10)
timer = setInterval(fireInterval.bind(null, data.id), time)
timers[data.id] = timer
},
clearInterval: function W_clearInterval(data) {
if (timers[data.id]) {
clearInterval(timers[data.id])
delete timers[data.id]
}
}
}
this.addEventListener('message', function(event) {
var data = event.data
if (commands[data.command]) {
commands[data.command](data)
}
})
// $interval + Web Worker
// to avoid background timer throttling by Chrome (and maybe other browsers)
// heavily adapted from https://gist.github.com/BinaryMuse/19aa812cd2277d8c9555
// returns an object that mostly behaves like $interval
// EXCEPT it just returns an id, not a promise
// (there may be other differences, but most of them would be downstream of this one)
//
// in browsers that don't support Worker, it just returns the $interval module
// either way, whatever it returns is still the thing to pass to .cancel()
app.provider('winterval', function WintervalProvider() {
function isDefined(value) {return typeof value !== 'undefined'}
this.$get = ['$rootScope', '$interval',
function($rootScope, $interval) {
if (typeof(Worker) == 'undefined') {
return $interval
}
var timers = {}
var intervalId = 0
var worker = new Worker('/interval-worker.js')
worker.addEventListener('message', function (event) {
var data = event.data
var id = data.id
var timer = timers[id]
if (timer) {
var count = timer.count
var fn = timer.fn
var args = timer.args
if (timer.count > 0 && timer.iteration >= timer.count) {
worker.postMessage({command: "clearInterval", id: id})
delete timers[id]
}
if (!timer.skipApply) $rootScope.$apply()
fn.apply(null, args)
} else {
console.log("worker attempted to access nonexistent timer")
worker.postMessage({command: "clearInterval", id: id})
}
})
function winterval(fn, delay, count, invokeApply) {
intervalId += 1
delay = delay || 0
var id = intervalId
timers[id] = {
fn: fn,
iteration: 0,
count: isDefined(count) ? count : 0,
skipApply: (isDefined(invokeApply) && !invokeApply)
// args: args
}
worker.postMessage({command: "setInterval", id: id, time: delay, count: count})
return id
}
winterval.cancel = function (id) {
if (timers[id]) {
worker.postMessage({command: "clearInterval", id: id})
delete timers[id]
return true
}
return false
}
return winterval
}]
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment