asap.js 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. // Use the fastest possible means to execute a task in a future turn
  2. // of the event loop.
  3. // linked list of tasks (single, with head node)
  4. var head = {task: void 0, next: null};
  5. var tail = head;
  6. var flushing = false;
  7. var requestFlush = void 0;
  8. var isNodeJS = false;
  9. function flush() {
  10. /* jshint loopfunc: true */
  11. while (head.next) {
  12. head = head.next;
  13. var task = head.task;
  14. head.task = void 0;
  15. var domain = head.domain;
  16. if (domain) {
  17. head.domain = void 0;
  18. domain.enter();
  19. }
  20. try {
  21. task();
  22. } catch (e) {
  23. if (isNodeJS) {
  24. // In node, uncaught exceptions are considered fatal errors.
  25. // Re-throw them synchronously to interrupt flushing!
  26. // Ensure continuation if the uncaught exception is suppressed
  27. // listening "uncaughtException" events (as domains does).
  28. // Continue in next event to avoid tick recursion.
  29. if (domain) {
  30. domain.exit();
  31. }
  32. setTimeout(flush, 0);
  33. if (domain) {
  34. domain.enter();
  35. }
  36. throw e;
  37. } else {
  38. // In browsers, uncaught exceptions are not fatal.
  39. // Re-throw them asynchronously to avoid slow-downs.
  40. setTimeout(function() {
  41. throw e;
  42. }, 0);
  43. }
  44. }
  45. if (domain) {
  46. domain.exit();
  47. }
  48. }
  49. flushing = false;
  50. }
  51. if (typeof process !== "undefined" && process.nextTick) {
  52. // Node.js before 0.9. Note that some fake-Node environments, like the
  53. // Mocha test runner, introduce a `process` global without a `nextTick`.
  54. isNodeJS = true;
  55. requestFlush = function () {
  56. process.nextTick(flush);
  57. };
  58. } else if (typeof setImmediate === "function") {
  59. // In IE10, Node.js 0.9+, or https://github.com/NobleJS/setImmediate
  60. if (typeof window !== "undefined") {
  61. requestFlush = setImmediate.bind(window, flush);
  62. } else {
  63. requestFlush = function () {
  64. setImmediate(flush);
  65. };
  66. }
  67. } else if (typeof MessageChannel !== "undefined") {
  68. // modern browsers
  69. // http://www.nonblocking.io/2011/06/windownexttick.html
  70. var channel = new MessageChannel();
  71. channel.port1.onmessage = flush;
  72. requestFlush = function () {
  73. channel.port2.postMessage(0);
  74. };
  75. } else {
  76. // old browsers
  77. requestFlush = function () {
  78. setTimeout(flush, 0);
  79. };
  80. }
  81. function asap(task) {
  82. tail = tail.next = {
  83. task: task,
  84. domain: isNodeJS && process.domain,
  85. next: null
  86. };
  87. if (!flushing) {
  88. flushing = true;
  89. requestFlush();
  90. }
  91. };
  92. module.exports = asap;