Blame view

node_modules/asap/raw.js 4.04 KB
ce4c83ff   wxy   初始提交
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
  "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;
      }
  }