async.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. "use strict";
  2. var firstLineError;
  3. try {throw new Error(); } catch (e) {firstLineError = e;}
  4. var schedule = require("./schedule.js");
  5. var Queue = require("./queue.js");
  6. var util = require("./util.js");
  7. function Async() {
  8. this._isTickUsed = false;
  9. this._lateQueue = new Queue(16);
  10. this._normalQueue = new Queue(16);
  11. this._trampolineEnabled = true;
  12. var self = this;
  13. this.drainQueues = function () {
  14. self._drainQueues();
  15. };
  16. this._schedule =
  17. schedule.isStatic ? schedule(this.drainQueues) : schedule;
  18. }
  19. Async.prototype.disableTrampolineIfNecessary = function() {
  20. if (util.hasDevTools) {
  21. this._trampolineEnabled = false;
  22. }
  23. };
  24. Async.prototype.enableTrampoline = function() {
  25. if (!this._trampolineEnabled) {
  26. this._trampolineEnabled = true;
  27. this._schedule = function(fn) {
  28. setTimeout(fn, 0);
  29. };
  30. }
  31. };
  32. Async.prototype.haveItemsQueued = function () {
  33. return this._normalQueue.length() > 0;
  34. };
  35. Async.prototype.throwLater = function(fn, arg) {
  36. if (arguments.length === 1) {
  37. arg = fn;
  38. fn = function () { throw arg; };
  39. }
  40. var domain = this._getDomain();
  41. if (domain !== undefined) fn = domain.bind(fn);
  42. if (typeof setTimeout !== "undefined") {
  43. setTimeout(function() {
  44. fn(arg);
  45. }, 0);
  46. } else try {
  47. this._schedule(function() {
  48. fn(arg);
  49. });
  50. } catch (e) {
  51. throw new Error("No async scheduler available\u000a\u000a See http://goo.gl/m3OTXk\u000a");
  52. }
  53. };
  54. Async.prototype._getDomain = function() {};
  55. if (!false) {
  56. if (util.isNode) {
  57. var EventsModule = require("events");
  58. var domainGetter = function() {
  59. var domain = process.domain;
  60. if (domain === null) return undefined;
  61. return domain;
  62. };
  63. if (EventsModule.usingDomains) {
  64. Async.prototype._getDomain = domainGetter;
  65. } else {
  66. var descriptor =
  67. Object.getOwnPropertyDescriptor(EventsModule, "usingDomains");
  68. if (descriptor) {
  69. if (!descriptor.configurable) {
  70. process.on("domainsActivated", function() {
  71. Async.prototype._getDomain = domainGetter;
  72. });
  73. } else {
  74. var usingDomains = false;
  75. Object.defineProperty(EventsModule, "usingDomains", {
  76. configurable: false,
  77. enumerable: true,
  78. get: function() {
  79. return usingDomains;
  80. },
  81. set: function(value) {
  82. if (usingDomains || !value) return;
  83. usingDomains = true;
  84. Async.prototype._getDomain = domainGetter;
  85. util.toFastProperties(process);
  86. process.emit("domainsActivated");
  87. }
  88. });
  89. }
  90. }
  91. }
  92. }
  93. }
  94. function AsyncInvokeLater(fn, receiver, arg) {
  95. var domain = this._getDomain();
  96. if (domain !== undefined) fn = domain.bind(fn);
  97. this._lateQueue.push(fn, receiver, arg);
  98. this._queueTick();
  99. }
  100. function AsyncInvoke(fn, receiver, arg) {
  101. var domain = this._getDomain();
  102. if (domain !== undefined) fn = domain.bind(fn);
  103. this._normalQueue.push(fn, receiver, arg);
  104. this._queueTick();
  105. }
  106. function AsyncSettlePromises(promise) {
  107. var domain = this._getDomain();
  108. if (domain !== undefined) {
  109. var fn = domain.bind(promise._settlePromises);
  110. this._normalQueue.push(fn, promise, undefined);
  111. } else {
  112. this._normalQueue._pushOne(promise);
  113. }
  114. this._queueTick();
  115. }
  116. if (!util.hasDevTools) {
  117. Async.prototype.invokeLater = AsyncInvokeLater;
  118. Async.prototype.invoke = AsyncInvoke;
  119. Async.prototype.settlePromises = AsyncSettlePromises;
  120. } else {
  121. Async.prototype.invokeLater = function (fn, receiver, arg) {
  122. if (this._trampolineEnabled) {
  123. AsyncInvokeLater.call(this, fn, receiver, arg);
  124. } else {
  125. setTimeout(function() {
  126. fn.call(receiver, arg);
  127. }, 100);
  128. }
  129. };
  130. Async.prototype.invoke = function (fn, receiver, arg) {
  131. if (this._trampolineEnabled) {
  132. AsyncInvoke.call(this, fn, receiver, arg);
  133. } else {
  134. setTimeout(function() {
  135. fn.call(receiver, arg);
  136. }, 0);
  137. }
  138. };
  139. Async.prototype.settlePromises = function(promise) {
  140. if (this._trampolineEnabled) {
  141. AsyncSettlePromises.call(this, promise);
  142. } else {
  143. setTimeout(function() {
  144. promise._settlePromises();
  145. }, 0);
  146. }
  147. };
  148. }
  149. Async.prototype.invokeFirst = function (fn, receiver, arg) {
  150. var domain = this._getDomain();
  151. if (domain !== undefined) fn = domain.bind(fn);
  152. this._normalQueue.unshift(fn, receiver, arg);
  153. this._queueTick();
  154. };
  155. Async.prototype._drainQueue = function(queue) {
  156. while (queue.length() > 0) {
  157. var fn = queue.shift();
  158. if (typeof fn !== "function") {
  159. fn._settlePromises();
  160. continue;
  161. }
  162. var receiver = queue.shift();
  163. var arg = queue.shift();
  164. fn.call(receiver, arg);
  165. }
  166. };
  167. Async.prototype._drainQueues = function () {
  168. this._drainQueue(this._normalQueue);
  169. this._reset();
  170. this._drainQueue(this._lateQueue);
  171. };
  172. Async.prototype._queueTick = function () {
  173. if (!this._isTickUsed) {
  174. this._isTickUsed = true;
  175. this._schedule(this.drainQueues);
  176. }
  177. };
  178. Async.prototype._reset = function () {
  179. this._isTickUsed = false;
  180. };
  181. module.exports = new Async();
  182. module.exports.firstLineError = firstLineError;