166 lines
4 KiB
JavaScript
166 lines
4 KiB
JavaScript
|
"use strict";
|
||
|
var firstLineError;
|
||
|
try {throw new Error(); } catch (e) {firstLineError = e;}
|
||
|
var schedule = require("./schedule");
|
||
|
var Queue = require("./queue");
|
||
|
var util = require("./util");
|
||
|
|
||
|
function Async() {
|
||
|
this._customScheduler = false;
|
||
|
this._isTickUsed = false;
|
||
|
this._lateQueue = new Queue(16);
|
||
|
this._normalQueue = new Queue(16);
|
||
|
this._haveDrainedQueues = false;
|
||
|
this._trampolineEnabled = true;
|
||
|
var self = this;
|
||
|
this.drainQueues = function () {
|
||
|
self._drainQueues();
|
||
|
};
|
||
|
this._schedule = schedule;
|
||
|
}
|
||
|
|
||
|
Async.prototype.setScheduler = function(fn) {
|
||
|
var prev = this._schedule;
|
||
|
this._schedule = fn;
|
||
|
this._customScheduler = true;
|
||
|
return prev;
|
||
|
};
|
||
|
|
||
|
Async.prototype.hasCustomScheduler = function() {
|
||
|
return this._customScheduler;
|
||
|
};
|
||
|
|
||
|
Async.prototype.enableTrampoline = function() {
|
||
|
this._trampolineEnabled = true;
|
||
|
};
|
||
|
|
||
|
Async.prototype.disableTrampolineIfNecessary = function() {
|
||
|
if (util.hasDevTools) {
|
||
|
this._trampolineEnabled = false;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
Async.prototype.haveItemsQueued = function () {
|
||
|
return this._isTickUsed || this._haveDrainedQueues;
|
||
|
};
|
||
|
|
||
|
|
||
|
Async.prototype.fatalError = function(e, isNode) {
|
||
|
if (isNode) {
|
||
|
process.stderr.write("Fatal " + (e instanceof Error ? e.stack : e) +
|
||
|
"\n");
|
||
|
process.exit(2);
|
||
|
} else {
|
||
|
this.throwLater(e);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
Async.prototype.throwLater = function(fn, arg) {
|
||
|
if (arguments.length === 1) {
|
||
|
arg = fn;
|
||
|
fn = function () { throw arg; };
|
||
|
}
|
||
|
if (typeof setTimeout !== "undefined") {
|
||
|
setTimeout(function() {
|
||
|
fn(arg);
|
||
|
}, 0);
|
||
|
} else try {
|
||
|
this._schedule(function() {
|
||
|
fn(arg);
|
||
|
});
|
||
|
} catch (e) {
|
||
|
throw new Error("No async scheduler available\u000a\u000a See http://goo.gl/MqrFmX\u000a");
|
||
|
}
|
||
|
};
|
||
|
|
||
|
function AsyncInvokeLater(fn, receiver, arg) {
|
||
|
this._lateQueue.push(fn, receiver, arg);
|
||
|
this._queueTick();
|
||
|
}
|
||
|
|
||
|
function AsyncInvoke(fn, receiver, arg) {
|
||
|
this._normalQueue.push(fn, receiver, arg);
|
||
|
this._queueTick();
|
||
|
}
|
||
|
|
||
|
function AsyncSettlePromises(promise) {
|
||
|
this._normalQueue._pushOne(promise);
|
||
|
this._queueTick();
|
||
|
}
|
||
|
|
||
|
if (!util.hasDevTools) {
|
||
|
Async.prototype.invokeLater = AsyncInvokeLater;
|
||
|
Async.prototype.invoke = AsyncInvoke;
|
||
|
Async.prototype.settlePromises = AsyncSettlePromises;
|
||
|
} else {
|
||
|
Async.prototype.invokeLater = function (fn, receiver, arg) {
|
||
|
if (this._trampolineEnabled) {
|
||
|
AsyncInvokeLater.call(this, fn, receiver, arg);
|
||
|
} else {
|
||
|
this._schedule(function() {
|
||
|
setTimeout(function() {
|
||
|
fn.call(receiver, arg);
|
||
|
}, 100);
|
||
|
});
|
||
|
}
|
||
|
};
|
||
|
|
||
|
Async.prototype.invoke = function (fn, receiver, arg) {
|
||
|
if (this._trampolineEnabled) {
|
||
|
AsyncInvoke.call(this, fn, receiver, arg);
|
||
|
} else {
|
||
|
this._schedule(function() {
|
||
|
fn.call(receiver, arg);
|
||
|
});
|
||
|
}
|
||
|
};
|
||
|
|
||
|
Async.prototype.settlePromises = function(promise) {
|
||
|
if (this._trampolineEnabled) {
|
||
|
AsyncSettlePromises.call(this, promise);
|
||
|
} else {
|
||
|
this._schedule(function() {
|
||
|
promise._settlePromises();
|
||
|
});
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
|
||
|
function _drainQueue(queue) {
|
||
|
while (queue.length() > 0) {
|
||
|
_drainQueueStep(queue);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function _drainQueueStep(queue) {
|
||
|
var fn = queue.shift();
|
||
|
if (typeof fn !== "function") {
|
||
|
fn._settlePromises();
|
||
|
} else {
|
||
|
var receiver = queue.shift();
|
||
|
var arg = queue.shift();
|
||
|
fn.call(receiver, arg);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Async.prototype._drainQueues = function () {
|
||
|
_drainQueue(this._normalQueue);
|
||
|
this._reset();
|
||
|
this._haveDrainedQueues = true;
|
||
|
_drainQueue(this._lateQueue);
|
||
|
};
|
||
|
|
||
|
Async.prototype._queueTick = function () {
|
||
|
if (!this._isTickUsed) {
|
||
|
this._isTickUsed = true;
|
||
|
this._schedule(this.drainQueues);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
Async.prototype._reset = function () {
|
||
|
this._isTickUsed = false;
|
||
|
};
|
||
|
|
||
|
module.exports = Async;
|
||
|
module.exports.firstLineError = firstLineError;
|