1'use strict' 2 3let fastNow = Date.now() 4let fastNowTimeout 5 6const fastTimers = [] 7 8function onTimeout () { 9 fastNow = Date.now() 10 11 let len = fastTimers.length 12 let idx = 0 13 while (idx < len) { 14 const timer = fastTimers[idx] 15 16 if (timer.state === 0) { 17 timer.state = fastNow + timer.delay 18 } else if (timer.state > 0 && fastNow >= timer.state) { 19 timer.state = -1 20 timer.callback(timer.opaque) 21 } 22 23 if (timer.state === -1) { 24 timer.state = -2 25 if (idx !== len - 1) { 26 fastTimers[idx] = fastTimers.pop() 27 } else { 28 fastTimers.pop() 29 } 30 len -= 1 31 } else { 32 idx += 1 33 } 34 } 35 36 if (fastTimers.length > 0) { 37 refreshTimeout() 38 } 39} 40 41function refreshTimeout () { 42 if (fastNowTimeout && fastNowTimeout.refresh) { 43 fastNowTimeout.refresh() 44 } else { 45 clearTimeout(fastNowTimeout) 46 fastNowTimeout = setTimeout(onTimeout, 1e3) 47 if (fastNowTimeout.unref) { 48 fastNowTimeout.unref() 49 } 50 } 51} 52 53class Timeout { 54 constructor (callback, delay, opaque) { 55 this.callback = callback 56 this.delay = delay 57 this.opaque = opaque 58 59 // -2 not in timer list 60 // -1 in timer list but inactive 61 // 0 in timer list waiting for time 62 // > 0 in timer list waiting for time to expire 63 this.state = -2 64 65 this.refresh() 66 } 67 68 refresh () { 69 if (this.state === -2) { 70 fastTimers.push(this) 71 if (!fastNowTimeout || fastTimers.length === 1) { 72 refreshTimeout() 73 } 74 } 75 76 this.state = 0 77 } 78 79 clear () { 80 this.state = -1 81 } 82} 83 84module.exports = { 85 setTimeout (callback, delay, opaque) { 86 return delay < 1e3 87 ? setTimeout(callback, delay, opaque) 88 : new Timeout(callback, delay, opaque) 89 }, 90 clearTimeout (timeout) { 91 if (timeout instanceof Timeout) { 92 timeout.clear() 93 } else { 94 clearTimeout(timeout) 95 } 96 } 97} 98