UNPKG

2.43 kBJavaScriptView Raw
1/* global requestIdleCallback, requestAnimationFrame, cancelIdleCallback, cancelAnimationFrame */
2
3/**
4 * Utility module to work with EcmaScript's event loop.
5 *
6 * @module eventloop
7 */
8
9/**
10 * @type {Array<function>}
11 */
12let queue = []
13
14const _runQueue = () => {
15 for (let i = 0; i < queue.length; i++) {
16 queue[i]()
17 }
18 queue = []
19}
20
21/**
22 * @param {function():void} f
23 */
24export const enqueue = f => {
25 queue.push(f)
26 if (queue.length === 1) {
27 setTimeout(_runQueue, 0)
28 }
29}
30
31/**
32 * @typedef {Object} TimeoutObject
33 * @property {function} TimeoutObject.destroy
34 */
35
36/**
37 * @param {function(number):void} clearFunction
38 */
39const createTimeoutClass = clearFunction => class TT {
40 /**
41 * @param {number} timeoutId
42 */
43 constructor (timeoutId) {
44 this._ = timeoutId
45 }
46
47 destroy () {
48 clearFunction(this._)
49 }
50}
51
52const Timeout = createTimeoutClass(clearTimeout)
53
54/**
55 * @param {number} timeout
56 * @param {function} callback
57 * @return {TimeoutObject}
58 */
59export const timeout = (timeout, callback) => new Timeout(setTimeout(callback, timeout))
60
61const Interval = createTimeoutClass(clearInterval)
62
63/**
64 * @param {number} timeout
65 * @param {function} callback
66 * @return {TimeoutObject}
67 */
68export const interval = (timeout, callback) => new Interval(setInterval(callback, timeout))
69
70/* c8 ignore next */
71export const Animation = createTimeoutClass(arg => typeof requestAnimationFrame !== 'undefined' && cancelAnimationFrame(arg))
72
73/**
74 * @param {function(number):void} cb
75 * @return {TimeoutObject}
76 */
77/* c8 ignore next */
78export const animationFrame = cb => typeof requestAnimationFrame === 'undefined' ? timeout(0, cb) : new Animation(requestAnimationFrame(cb))
79
80/* c8 ignore next */
81// @ts-ignore
82const Idle = createTimeoutClass(arg => typeof cancelIdleCallback !== 'undefined' && cancelIdleCallback(arg))
83
84/**
85 * Note: this is experimental and is probably only useful in browsers.
86 *
87 * @param {function} cb
88 * @return {TimeoutObject}
89 */
90/* c8 ignore next 2 */
91// @ts-ignore
92export const idleCallback = cb => typeof requestIdleCallback !== 'undefined' ? new Idle(requestIdleCallback(cb)) : timeout(1000, cb)
93
94/**
95 * @param {number} timeout Timeout of the debounce action
96 * @return {function(function():void):void}
97 */
98export const createDebouncer = timeout => {
99 let timer = -1
100 return f => {
101 clearTimeout(timer)
102 if (f) {
103 timer = /** @type {any} */ (setTimeout(f, timeout))
104 }
105 }
106}