Newer
Older
/**
* Copyright (c) 2017 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
/**
* setImmediate polyfill adapted from https://github.com/YuzuJS/setImmediate
* Copyright (c) 2012 Barnesandnoble.com, llc, Donavon West, and Domenic Denicola
* MIT license.
*/
const global: any = (function () {
const _window = typeof window !== 'undefined' && window;
const _self = typeof self !== 'undefined' && typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope && self;
const _global = typeof global !== 'undefined' && global;
return _window || _global || _self;
})();
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
type Callback = (...args: any[]) => void;
type Task = { callback: Callback, args: any[] }
const tasksByHandle: { [handle: number]: Task } = { };
const doc = typeof document !== 'undefined' ? document : void 0;
let nextHandle = 1; // Spec says greater than zero
let registerImmediate: ((handle: number) => void);
function setImmediate(callback: Callback, ...args: any[]) {
// Callback can either be a function or a string
if (typeof callback !== 'function') {
callback = new Function('' + callback) as Callback;
}
// Store and register the task
const task = { callback: callback, args: args };
tasksByHandle[nextHandle] = task;
registerImmediate(nextHandle);
return nextHandle++;
}
function clearImmediate(handle: number) {
delete tasksByHandle[handle];
}
function run(task: Task) {
const callback = task.callback;
const args = task.args;
switch (args.length) {
case 0:
callback();
break;
case 1:
callback(args[0]);
break;
case 2:
callback(args[0], args[1]);
break;
case 3:
callback(args[0], args[1], args[2]);
break;
default:
callback.apply(undefined, args);
break;
}
}
function runIfPresent(handle: number) {
const task = tasksByHandle[handle];
clearImmediate(handle);
run(task);
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
}
function installNextTickImplementation() {
registerImmediate = function(handle) {
process.nextTick(function () { runIfPresent(handle); });
};
}
function canUsePostMessage() {
if (global && global.postMessage && !global.importScripts) {
let postMessageIsAsynchronous = true;
const oldOnMessage = global.onmessage;
global.onmessage = function() {
postMessageIsAsynchronous = false;
};
global.postMessage('', '*');
global.onmessage = oldOnMessage;
return postMessageIsAsynchronous;
}
}
function installPostMessageImplementation() {
// Installs an event handler on `global` for the `message` event: see
// * https://developer.mozilla.org/en/DOM/window.postMessage
// * http://www.whatwg.org/specs/web-apps/current-work/multipage/comms.html#crossDocumentMessages
const messagePrefix = 'setImmediate$' + Math.random() + '$';
const onGlobalMessage = function(event: any) {
if (event.source === global &&
typeof event.data === 'string' &&
event.data.indexOf(messagePrefix) === 0) {
runIfPresent(+event.data.slice(messagePrefix.length));
}
};
if (window.addEventListener) {
window.addEventListener('message', onGlobalMessage, false);
} else {
(window as any).attachEvent('onmessage', onGlobalMessage);
}
registerImmediate = function(handle) {
window.postMessage(messagePrefix + handle, '*');
};
}
function installMessageChannelImplementation() {
const channel = new MessageChannel();
channel.port1.onmessage = function(event) {
const handle = event.data;
runIfPresent(handle);
};
registerImmediate = function(handle) {
channel.port2.postMessage(handle);
};
}
function installReadyStateChangeImplementation() {
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
registerImmediate = function(handle) {
// Create a <script> element; its readystatechange event will be fired asynchronously once it is inserted
// into the document. Do so, thus queuing up the task. Remember to clean up once it's been called.
let script = doc!.createElement('script') as any;
script.onreadystatechange = function () {
runIfPresent(handle);
script.onreadystatechange = null;
html.removeChild(script);
script = null;
};
html.appendChild(script);
};
}
function installSetTimeoutImplementation() {
registerImmediate = function(handle) {
setTimeout(runIfPresent, 0, handle);
};
}
// Don't get fooled by e.g. browserify environments.
if (typeof process !== 'undefined' && {}.toString.call(process) === '[object process]') {
// For Node.js before 0.9
installNextTickImplementation();
} else if (canUsePostMessage()) {
// For non-IE10 modern browsers
installPostMessageImplementation();
} else if (typeof MessageChannel !== 'undefined') {
// For web workers, where supported
installMessageChannelImplementation();
} else if (doc && 'onreadystatechange' in doc.createElement('script')) {
// For IE 6–8
installReadyStateChangeImplementation();
} else {
// For older browsers
installSetTimeoutImplementation();
}
return {
setImmediate,
clearImmediate
};
}
const immediateActions = (function () {
if (typeof setImmediate !== 'undefined') {
if (typeof window !== 'undefined') {
setImmediate: (handler: any, ...args: any[]) => (window as any).setImmediate(handler, ...args as any) as number,
clearImmediate: (handle: any) => (window as any).clearImmediate(handle)
};
} else {
return { setImmediate, clearImmediate }
}
}
return createImmediateActions();
}());
function resolveImmediate(res: () => void) {
immediateActions.setImmediate(res);
}
const Scheduler = {
setImmediate: immediateActions.setImmediate,
immediatePromise() { return new Promise<void>(resolveImmediate); },
delay<T>(timeout: number, value: T | undefined = void 0): Promise<T> { return new Promise(r => setTimeout(r, timeout, value)) }
}