| "use strict"; |
| var firstLineError; |
| try {throw new Error(); } catch (e) {firstLineError = e;} |
| var schedule = require("./schedule"); |
| var Queue = require("./queue"); |
| |
| function Async() { |
| this._customScheduler = false; |
| this._isTickUsed = false; |
| this._lateQueue = new Queue(16); |
| this._normalQueue = new Queue(16); |
| this._haveDrainedQueues = false; |
| 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.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(); |
| } |
| |
| Async.prototype.invokeLater = AsyncInvokeLater; |
| Async.prototype.invoke = AsyncInvoke; |
| Async.prototype.settlePromises = AsyncSettlePromises; |
| |
| |
| 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; |