asap.js 1.9 KB

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