async.js (2876B)
1 "use strict"; 2 var firstLineError; 3 try {throw new Error(); } catch (e) {firstLineError = e;} 4 var schedule = require("./schedule"); 5 var Queue = require("./queue"); 6 7 function Async() { 8 this._customScheduler = false; 9 this._isTickUsed = false; 10 this._lateQueue = new Queue(16); 11 this._normalQueue = new Queue(16); 12 this._haveDrainedQueues = false; 13 var self = this; 14 this.drainQueues = function () { 15 self._drainQueues(); 16 }; 17 this._schedule = schedule; 18 } 19 20 Async.prototype.setScheduler = function(fn) { 21 var prev = this._schedule; 22 this._schedule = fn; 23 this._customScheduler = true; 24 return prev; 25 }; 26 27 Async.prototype.hasCustomScheduler = function() { 28 return this._customScheduler; 29 }; 30 31 Async.prototype.haveItemsQueued = function () { 32 return this._isTickUsed || this._haveDrainedQueues; 33 }; 34 35 36 Async.prototype.fatalError = function(e, isNode) { 37 if (isNode) { 38 process.stderr.write("Fatal " + (e instanceof Error ? e.stack : e) + 39 "\n"); 40 process.exit(2); 41 } else { 42 this.throwLater(e); 43 } 44 }; 45 46 Async.prototype.throwLater = function(fn, arg) { 47 if (arguments.length === 1) { 48 arg = fn; 49 fn = function () { throw arg; }; 50 } 51 if (typeof setTimeout !== "undefined") { 52 setTimeout(function() { 53 fn(arg); 54 }, 0); 55 } else try { 56 this._schedule(function() { 57 fn(arg); 58 }); 59 } catch (e) { 60 throw new Error("No async scheduler available\u000a\u000a See http://goo.gl/MqrFmX\u000a"); 61 } 62 }; 63 64 function AsyncInvokeLater(fn, receiver, arg) { 65 this._lateQueue.push(fn, receiver, arg); 66 this._queueTick(); 67 } 68 69 function AsyncInvoke(fn, receiver, arg) { 70 this._normalQueue.push(fn, receiver, arg); 71 this._queueTick(); 72 } 73 74 function AsyncSettlePromises(promise) { 75 this._normalQueue._pushOne(promise); 76 this._queueTick(); 77 } 78 79 Async.prototype.invokeLater = AsyncInvokeLater; 80 Async.prototype.invoke = AsyncInvoke; 81 Async.prototype.settlePromises = AsyncSettlePromises; 82 83 84 function _drainQueue(queue) { 85 while (queue.length() > 0) { 86 _drainQueueStep(queue); 87 } 88 } 89 90 function _drainQueueStep(queue) { 91 var fn = queue.shift(); 92 if (typeof fn !== "function") { 93 fn._settlePromises(); 94 } else { 95 var receiver = queue.shift(); 96 var arg = queue.shift(); 97 fn.call(receiver, arg); 98 } 99 } 100 101 Async.prototype._drainQueues = function () { 102 _drainQueue(this._normalQueue); 103 this._reset(); 104 this._haveDrainedQueues = true; 105 _drainQueue(this._lateQueue); 106 }; 107 108 Async.prototype._queueTick = function () { 109 if (!this._isTickUsed) { 110 this._isTickUsed = true; 111 this._schedule(this.drainQueues); 112 } 113 }; 114 115 Async.prototype._reset = function () { 116 this._isTickUsed = false; 117 }; 118 119 module.exports = Async; 120 module.exports.firstLineError = firstLineError;