Paul Lewis | 911c1b8 | 2019-12-02 12:46:15 | [diff] [blame] | 1 | "use strict"; |
| 2 | |
| 3 | var rawAsap = require("./raw"); |
| 4 | var freeTasks = []; |
| 5 | |
| 6 | /** |
| 7 | * Calls a task as soon as possible after returning, in its own event, with |
| 8 | * priority over IO events. An exception thrown in a task can be handled by |
| 9 | * `process.on("uncaughtException") or `domain.on("error")`, but will otherwise |
| 10 | * crash the process. If the error is handled, all subsequent tasks will |
| 11 | * resume. |
| 12 | * |
| 13 | * @param {{call}} task A callable object, typically a function that takes no |
| 14 | * arguments. |
| 15 | */ |
| 16 | module.exports = asap; |
| 17 | function asap(task) { |
| 18 | var rawTask; |
| 19 | if (freeTasks.length) { |
| 20 | rawTask = freeTasks.pop(); |
| 21 | } else { |
| 22 | rawTask = new RawTask(); |
| 23 | } |
| 24 | rawTask.task = task; |
| 25 | rawTask.domain = process.domain; |
| 26 | rawAsap(rawTask); |
| 27 | } |
| 28 | |
| 29 | function RawTask() { |
| 30 | this.task = null; |
| 31 | this.domain = null; |
| 32 | } |
| 33 | |
| 34 | RawTask.prototype.call = function () { |
| 35 | if (this.domain) { |
| 36 | this.domain.enter(); |
| 37 | } |
| 38 | var threw = true; |
| 39 | try { |
| 40 | this.task.call(); |
| 41 | threw = false; |
| 42 | // If the task throws an exception (presumably) Node.js restores the |
| 43 | // domain stack for the next event. |
| 44 | if (this.domain) { |
| 45 | this.domain.exit(); |
| 46 | } |
| 47 | } finally { |
| 48 | // We use try/finally and a threw flag to avoid messing up stack traces |
| 49 | // when we catch and release errors. |
| 50 | if (threw) { |
| 51 | // In Node.js, uncaught exceptions are considered fatal errors. |
| 52 | // Re-throw them to interrupt flushing! |
| 53 | // Ensure that flushing continues if an uncaught exception is |
| 54 | // suppressed listening process.on("uncaughtException") or |
| 55 | // domain.on("error"). |
| 56 | rawAsap.requestFlush(); |
| 57 | } |
| 58 | // If the task threw an error, we do not want to exit the domain here. |
| 59 | // Exiting the domain would prevent the domain from catching the error. |
| 60 | this.task = null; |
| 61 | this.domain = null; |
| 62 | freeTasks.push(this); |
| 63 | } |
| 64 | }; |
| 65 | |