| "use strict"; |
| |
| var domain; // The domain module is executed on demand |
| var hasSetImmediate = typeof setImmediate === "function"; |
| |
| // Use the fastest means possible to execute a task in its own turn, with |
| // priority over other events including network IO events in Node.js. |
| // |
| // An exception thrown by a task will permanently interrupt the processing of |
| // subsequent tasks. The higher level `asap` function ensures that if an |
| // exception is thrown by a task, that the task queue will continue flushing as |
| // soon as possible, but if you use `rawAsap` directly, you are responsible to |
| // either ensure that no exceptions are thrown from your task, or to manually |
| // call `rawAsap.requestFlush` if an exception is thrown. |
| module.exports = rawAsap; |
| function rawAsap(task) { |
| if (!queue.length) { |
| requestFlush(); |
| flushing = true; |
| } |
| // Avoids a function call |
| queue[queue.length] = task; |
| } |
| |
| var queue = []; |
| // Once a flush has been requested, no further calls to `requestFlush` are |
| // necessary until the next `flush` completes. |
| var flushing = false; |
| // The position of the next task to execute in the task queue. This is |
| // preserved between calls to `flush` so that it can be resumed if |
| // a task throws an exception. |
| var index = 0; |
| // If a task schedules additional tasks recursively, the task queue can grow |
| // unbounded. To prevent memory excaustion, the task queue will periodically |
| // truncate already-completed tasks. |
| var capacity = 1024; |
| |
| // The flush function processes all tasks that have been scheduled with |
| // `rawAsap` unless and until one of those tasks throws an exception. |
| // If a task throws an exception, `flush` ensures that its state will remain |
| // consistent and will resume where it left off when called again. |
| // However, `flush` does not make any arrangements to be called again if an |
| // exception is thrown. |
| function flush() { |
| while (index < queue.length) { |
| var currentIndex = index; |
| // Advance the index before calling the task. This ensures that we will |
| // begin flushing on the next task the task throws an error. |
| index = index + 1; |
| queue[currentIndex].call(); |
| // Prevent leaking memory for long chains of recursive calls to `asap`. |
| // If we call `asap` within tasks scheduled by `asap`, the queue will |
| // grow, but to avoid an O(n) walk for every task we execute, we don't |
| // shift tasks off the queue after they have been executed. |
| // Instead, we periodically shift 1024 tasks off the queue. |
| if (index > capacity) { |
| // Manually shift all values starting at the index back to the |
| // beginning of the queue. |
| for (var scan = 0, newLength = queue.length - index; scan < newLength; scan++) { |
| queue[scan] = queue[scan + index]; |
| } |
| queue.length -= index; |
| index = 0; |
| } |
| } |
| queue.length = 0; |
| index = 0; |
| flushing = false; |
| } |
| |
| rawAsap.requestFlush = requestFlush; |
| function requestFlush() { |
| // Ensure flushing is not bound to any domain. |
| // It is not sufficient to exit the domain, because domains exist on a stack. |
| // To execute code outside of any domain, the following dance is necessary. |
| var parentDomain = process.domain; |
| if (parentDomain) { |
| if (!domain) { |
| // Lazy execute the domain module. |
| // Only employed if the user elects to use domains. |
| domain = require("domain"); |
| } |
| domain.active = process.domain = null; |
| } |
| |
| // `setImmediate` is slower that `process.nextTick`, but `process.nextTick` |
| // cannot handle recursion. |
| // `requestFlush` will only be called recursively from `asap.js`, to resume |
| // flushing after an error is thrown into a domain. |
| // Conveniently, `setImmediate` was introduced in the same version |
| // `process.nextTick` started throwing recursion errors. |
| if (flushing && hasSetImmediate) { |
| setImmediate(flush); |
| } else { |
| process.nextTick(flush); |
| } |
| |
| if (parentDomain) { |
| domain.active = process.domain = parentDomain; |
| } |
| } |