Skip to content

Instantly share code, notes, and snippets.

@chrisdickinson
Last active August 29, 2015 14:05
Show Gist options
  • Save chrisdickinson/efd46d1a076c387b9340 to your computer and use it in GitHub Desktop.
Save chrisdickinson/efd46d1a076c387b9340 to your computer and use it in GitHub Desktop.
timers for runtime.js

runtime-timers

Timers (setTimeout and friends!) for RuntimeJS.

var timers = require('runtime-timers')

timers.install()

setInterval(function() {
  console.log('hello!')
}, 100)

while(true) {
  timers.update()
}
module.exports = {
update: update
, install: install
, setTimeout: globalTimeout
, setInterval: globalInterval
, setImmediate: globalImmediate
, clearTimeout: globalClearTimer
, clearInterval: globalClearTimer
, clearImmediate: globalClearTimer
}
function Timer(ms, cb, args) {
this._id = ++Timer.id
this._remainingMS = ms || 0
this._cb = cb
this._args = args
this._next = null
this._prev = null
}
Timer.id = 0
var insertTimer = defaultInsertTimer
var correctedAdd = 0
var queued = []
Timer.prototype.visit = function(fn, n) {
this._remainingMS -= n
fn(this)
if(this._next) {
this._next.visit(fn, n)
}
}
Timer.prototype.makeCallback = function() {
try {
if(typeof this._cb === 'string') {
return Function('return ' + this._cb)()
.apply(null, this._args)
}
this._cb.apply(null, this._args)
} catch(err) {
// what to do here?
}
this.remove()
}
Timer.prototype.remove = function() {
var last = this._prev
var next = this._next
if(last) {
last._next = next
} else {
currentTimer = next
}
if(next) {
next._prev = last
}
}
function install() {
setTimeout = globalTimeout
setInterval = globalInterval
setImmediate = globalImmediate
clearTimeout = globalClearTimer
clearInterval = globalClearTimer
clearImmediate = globalClearTimer
}
var lastMS = null
var currentTimer = null
function update() {
if(lastMS === null) {
lastMS = ticks()
return
}
var currentMS = ticks()
var delta = currentMS - lastMS
if(!delta) {
return
}
lastMS = currentMS
if(!currentTimer) {
return
}
insertTimer = deferredInsertTimer
queued.length = 0
var current = currentTimer
currentTimer = null
try {
while(current) {
current._remainingMS -= delta
if(current._remainingMS <= 0) {
current.makeCallback()
} else if(currentTimer === null) {
currentTimer = current
}
current = current._next
}
} finally {
insertTimer = defaultInsertTimer
queued.forEach(insertTimer)
}
}
function deferredInsertTimer(timer) {
queued.push(timer)
}
function defaultInsertTimer(timer) {
var ms = timer._remainingMS
if(!currentTimer) {
currentTimer = timer
return
}
var current = currentTimer
, last = null
while(current && current._remainingMS < ms) {
last = current
current = current._next
}
if(last) {
var tmp = last._next
last._next = timer
timer._prev = last
timer._next = tmp
if(tmp) {
tmp._prev = timer
}
} else if(current) {
timer._next = current
current._prev = timer
if(current === currentTimer) {
currentTimer = timer
}
}
}
function globalTimeout(cb, ms /* args */) {
var args = [].slice.call(arguments, 2)
var timer = new Timer(ms, cb, args)
insertTimer(timer)
return timer._id
}
function globalInterval(cb, ms /* args */) {
var args = [].slice.call(arguments, 2)
var timer = new Timer(ms, _wrap, args)
insertTimer(timer)
return timer._id
function _wrap() {
try {
cb.apply(this, args)
} catch(err) {
print(err.stack)
}
setImmediate(function() {
timer._remainingMS = ms
insertTimer(timer)
})
}
}
function globalImmediate(cb) {
return globalTimeout(cb, 0)
}
function globalClearTimer(id) {
var current = currentTimer
while(current) {
if(current._id === id) {
current.remove()
return
}
current = current._next
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment