209 lines
8.9 KiB
JavaScript
209 lines
8.9 KiB
JavaScript
|
/**
|
|||
|
Some credit for this helper goes to http://github.com/YuzuJS/setImmediate
|
|||
|
*/
|
|||
|
"use strict";
|
|||
|
var root_1 = require('./root');
|
|||
|
var ImmediateDefinition = (function () {
|
|||
|
function ImmediateDefinition(root) {
|
|||
|
this.root = root;
|
|||
|
if (root.setImmediate && typeof root.setImmediate === 'function') {
|
|||
|
this.setImmediate = root.setImmediate.bind(root);
|
|||
|
this.clearImmediate = root.clearImmediate.bind(root);
|
|||
|
}
|
|||
|
else {
|
|||
|
this.nextHandle = 1;
|
|||
|
this.tasksByHandle = {};
|
|||
|
this.currentlyRunningATask = false;
|
|||
|
// Don't get fooled by e.g. browserify environments.
|
|||
|
if (this.canUseProcessNextTick()) {
|
|||
|
// For Node.js before 0.9
|
|||
|
this.setImmediate = this.createProcessNextTickSetImmediate();
|
|||
|
}
|
|||
|
else if (this.canUsePostMessage()) {
|
|||
|
// For non-IE10 modern browsers
|
|||
|
this.setImmediate = this.createPostMessageSetImmediate();
|
|||
|
}
|
|||
|
else if (this.canUseMessageChannel()) {
|
|||
|
// For web workers, where supported
|
|||
|
this.setImmediate = this.createMessageChannelSetImmediate();
|
|||
|
}
|
|||
|
else if (this.canUseReadyStateChange()) {
|
|||
|
// For IE 6–8
|
|||
|
this.setImmediate = this.createReadyStateChangeSetImmediate();
|
|||
|
}
|
|||
|
else {
|
|||
|
// For older browsers
|
|||
|
this.setImmediate = this.createSetTimeoutSetImmediate();
|
|||
|
}
|
|||
|
var ci = function clearImmediate(handle) {
|
|||
|
delete clearImmediate.instance.tasksByHandle[handle];
|
|||
|
};
|
|||
|
ci.instance = this;
|
|||
|
this.clearImmediate = ci;
|
|||
|
}
|
|||
|
}
|
|||
|
ImmediateDefinition.prototype.identify = function (o) {
|
|||
|
return this.root.Object.prototype.toString.call(o);
|
|||
|
};
|
|||
|
ImmediateDefinition.prototype.canUseProcessNextTick = function () {
|
|||
|
return this.identify(this.root.process) === '[object process]';
|
|||
|
};
|
|||
|
ImmediateDefinition.prototype.canUseMessageChannel = function () {
|
|||
|
return Boolean(this.root.MessageChannel);
|
|||
|
};
|
|||
|
ImmediateDefinition.prototype.canUseReadyStateChange = function () {
|
|||
|
var document = this.root.document;
|
|||
|
return Boolean(document && 'onreadystatechange' in document.createElement('script'));
|
|||
|
};
|
|||
|
ImmediateDefinition.prototype.canUsePostMessage = function () {
|
|||
|
var root = this.root;
|
|||
|
// The test against `importScripts` prevents this implementation from being installed inside a web worker,
|
|||
|
// where `root.postMessage` means something completely different and can't be used for this purpose.
|
|||
|
if (root.postMessage && !root.importScripts) {
|
|||
|
var postMessageIsAsynchronous_1 = true;
|
|||
|
var oldOnMessage = root.onmessage;
|
|||
|
root.onmessage = function () {
|
|||
|
postMessageIsAsynchronous_1 = false;
|
|||
|
};
|
|||
|
root.postMessage('', '*');
|
|||
|
root.onmessage = oldOnMessage;
|
|||
|
return postMessageIsAsynchronous_1;
|
|||
|
}
|
|||
|
return false;
|
|||
|
};
|
|||
|
// This function accepts the same arguments as setImmediate, but
|
|||
|
// returns a function that requires no arguments.
|
|||
|
ImmediateDefinition.prototype.partiallyApplied = function (handler) {
|
|||
|
var args = [];
|
|||
|
for (var _i = 1; _i < arguments.length; _i++) {
|
|||
|
args[_i - 1] = arguments[_i];
|
|||
|
}
|
|||
|
var fn = function result() {
|
|||
|
var _a = result, handler = _a.handler, args = _a.args;
|
|||
|
if (typeof handler === 'function') {
|
|||
|
handler.apply(undefined, args);
|
|||
|
}
|
|||
|
else {
|
|||
|
(new Function('' + handler))();
|
|||
|
}
|
|||
|
};
|
|||
|
fn.handler = handler;
|
|||
|
fn.args = args;
|
|||
|
return fn;
|
|||
|
};
|
|||
|
ImmediateDefinition.prototype.addFromSetImmediateArguments = function (args) {
|
|||
|
this.tasksByHandle[this.nextHandle] = this.partiallyApplied.apply(undefined, args);
|
|||
|
return this.nextHandle++;
|
|||
|
};
|
|||
|
ImmediateDefinition.prototype.createProcessNextTickSetImmediate = function () {
|
|||
|
var fn = function setImmediate() {
|
|||
|
var instance = setImmediate.instance;
|
|||
|
var handle = instance.addFromSetImmediateArguments(arguments);
|
|||
|
instance.root.process.nextTick(instance.partiallyApplied(instance.runIfPresent, handle));
|
|||
|
return handle;
|
|||
|
};
|
|||
|
fn.instance = this;
|
|||
|
return fn;
|
|||
|
};
|
|||
|
ImmediateDefinition.prototype.createPostMessageSetImmediate = function () {
|
|||
|
// 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
|
|||
|
var root = this.root;
|
|||
|
var messagePrefix = 'setImmediate$' + root.Math.random() + '$';
|
|||
|
var onGlobalMessage = function globalMessageHandler(event) {
|
|||
|
var instance = globalMessageHandler.instance;
|
|||
|
if (event.source === root &&
|
|||
|
typeof event.data === 'string' &&
|
|||
|
event.data.indexOf(messagePrefix) === 0) {
|
|||
|
instance.runIfPresent(+event.data.slice(messagePrefix.length));
|
|||
|
}
|
|||
|
};
|
|||
|
onGlobalMessage.instance = this;
|
|||
|
root.addEventListener('message', onGlobalMessage, false);
|
|||
|
var fn = function setImmediate() {
|
|||
|
var _a = setImmediate, messagePrefix = _a.messagePrefix, instance = _a.instance;
|
|||
|
var handle = instance.addFromSetImmediateArguments(arguments);
|
|||
|
instance.root.postMessage(messagePrefix + handle, '*');
|
|||
|
return handle;
|
|||
|
};
|
|||
|
fn.instance = this;
|
|||
|
fn.messagePrefix = messagePrefix;
|
|||
|
return fn;
|
|||
|
};
|
|||
|
ImmediateDefinition.prototype.runIfPresent = function (handle) {
|
|||
|
// From the spec: 'Wait until any invocations of this algorithm started before this one have completed.'
|
|||
|
// So if we're currently running a task, we'll need to delay this invocation.
|
|||
|
if (this.currentlyRunningATask) {
|
|||
|
// Delay by doing a setTimeout. setImmediate was tried instead, but in Firefox 7 it generated a
|
|||
|
// 'too much recursion' error.
|
|||
|
this.root.setTimeout(this.partiallyApplied(this.runIfPresent, handle), 0);
|
|||
|
}
|
|||
|
else {
|
|||
|
var task = this.tasksByHandle[handle];
|
|||
|
if (task) {
|
|||
|
this.currentlyRunningATask = true;
|
|||
|
try {
|
|||
|
task();
|
|||
|
}
|
|||
|
finally {
|
|||
|
this.clearImmediate(handle);
|
|||
|
this.currentlyRunningATask = false;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
};
|
|||
|
ImmediateDefinition.prototype.createMessageChannelSetImmediate = function () {
|
|||
|
var _this = this;
|
|||
|
var channel = new this.root.MessageChannel();
|
|||
|
channel.port1.onmessage = function (event) {
|
|||
|
var handle = event.data;
|
|||
|
_this.runIfPresent(handle);
|
|||
|
};
|
|||
|
var fn = function setImmediate() {
|
|||
|
var _a = setImmediate, channel = _a.channel, instance = _a.instance;
|
|||
|
var handle = instance.addFromSetImmediateArguments(arguments);
|
|||
|
channel.port2.postMessage(handle);
|
|||
|
return handle;
|
|||
|
};
|
|||
|
fn.channel = channel;
|
|||
|
fn.instance = this;
|
|||
|
return fn;
|
|||
|
};
|
|||
|
ImmediateDefinition.prototype.createReadyStateChangeSetImmediate = function () {
|
|||
|
var fn = function setImmediate() {
|
|||
|
var instance = setImmediate.instance;
|
|||
|
var root = instance.root;
|
|||
|
var doc = root.document;
|
|||
|
var html = doc.documentElement;
|
|||
|
var handle = instance.addFromSetImmediateArguments(arguments);
|
|||
|
// 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.
|
|||
|
var script = doc.createElement('script');
|
|||
|
script.onreadystatechange = function () {
|
|||
|
instance.runIfPresent(handle);
|
|||
|
script.onreadystatechange = null;
|
|||
|
html.removeChild(script);
|
|||
|
script = null;
|
|||
|
};
|
|||
|
html.appendChild(script);
|
|||
|
return handle;
|
|||
|
};
|
|||
|
fn.instance = this;
|
|||
|
return fn;
|
|||
|
};
|
|||
|
ImmediateDefinition.prototype.createSetTimeoutSetImmediate = function () {
|
|||
|
var fn = function setImmediate() {
|
|||
|
var instance = setImmediate.instance;
|
|||
|
var handle = instance.addFromSetImmediateArguments(arguments);
|
|||
|
instance.root.setTimeout(instance.partiallyApplied(instance.runIfPresent, handle), 0);
|
|||
|
return handle;
|
|||
|
};
|
|||
|
fn.instance = this;
|
|||
|
return fn;
|
|||
|
};
|
|||
|
return ImmediateDefinition;
|
|||
|
}());
|
|||
|
exports.ImmediateDefinition = ImmediateDefinition;
|
|||
|
exports.Immediate = new ImmediateDefinition(root_1.root);
|
|||
|
//# sourceMappingURL=Immediate.js.map
|