You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

237 lines
9.9 KiB

  1. # ASAP
  2. [![Build Status](https://travis-ci.org/kriskowal/asap.png?branch=master)](https://travis-ci.org/kriskowal/asap)
  3. Promise and asynchronous observer libraries, as well as hand-rolled callback
  4. programs and libraries, often need a mechanism to postpone the execution of a
  5. callback until the next available event.
  6. (See [Designing API’s for Asynchrony][Zalgo].)
  7. The `asap` function executes a task **as soon as possible** but not before it
  8. returns, waiting only for the completion of the current event and previously
  9. scheduled tasks.
  10. ```javascript
  11. asap(function () {
  12. // ...
  13. });
  14. ```
  15. [Zalgo]: http://blog.izs.me/post/59142742143/designing-apis-for-asynchrony
  16. This CommonJS package provides an `asap` module that exports a function that
  17. executes a task function *as soon as possible*.
  18. ASAP strives to schedule events to occur before yielding for IO, reflow,
  19. or redrawing.
  20. Each event receives an independent stack, with only platform code in parent
  21. frames and the events run in the order they are scheduled.
  22. ASAP provides a fast event queue that will execute tasks until it is
  23. empty before yielding to the JavaScript engine's underlying event-loop.
  24. When a task gets added to a previously empty event queue, ASAP schedules a flush
  25. event, preferring for that event to occur before the JavaScript engine has an
  26. opportunity to perform IO tasks or rendering, thus making the first task and
  27. subsequent tasks semantically indistinguishable.
  28. ASAP uses a variety of techniques to preserve this invariant on different
  29. versions of browsers and Node.js.
  30. By design, ASAP prevents input events from being handled until the task
  31. queue is empty.
  32. If the process is busy enough, this may cause incoming connection requests to be
  33. dropped, and may cause existing connections to inform the sender to reduce the
  34. transmission rate or stall.
  35. ASAP allows this on the theory that, if there is enough work to do, there is no
  36. sense in looking for trouble.
  37. As a consequence, ASAP can interfere with smooth animation.
  38. If your task should be tied to the rendering loop, consider using
  39. `requestAnimationFrame` instead.
  40. A long sequence of tasks can also effect the long running script dialog.
  41. If this is a problem, you may be able to use ASAP’s cousin `setImmediate` to
  42. break long processes into shorter intervals and periodically allow the browser
  43. to breathe.
  44. `setImmediate` will yield for IO, reflow, and repaint events.
  45. It also returns a handler and can be canceled.
  46. For a `setImmediate` shim, consider [YuzuJS setImmediate][setImmediate].
  47. [setImmediate]: https://github.com/YuzuJS/setImmediate
  48. Take care.
  49. ASAP can sustain infinite recursive calls without warning.
  50. It will not halt from a stack overflow, and it will not consume unbounded
  51. memory.
  52. This is behaviorally equivalent to an infinite loop.
  53. Just as with infinite loops, you can monitor a Node.js process for this behavior
  54. with a heart-beat signal.
  55. As with infinite loops, a very small amount of caution goes a long way to
  56. avoiding problems.
  57. ```javascript
  58. function loop() {
  59. asap(loop);
  60. }
  61. loop();
  62. ```
  63. In browsers, if a task throws an exception, it will not interrupt the flushing
  64. of high-priority tasks.
  65. The exception will be postponed to a later, low-priority event to avoid
  66. slow-downs.
  67. In Node.js, if a task throws an exception, ASAP will resume flushing only if—and
  68. only after—the error is handled by `domain.on("error")` or
  69. `process.on("uncaughtException")`.
  70. ## Raw ASAP
  71. Checking for exceptions comes at a cost.
  72. The package also provides an `asap/raw` module that exports the underlying
  73. implementation which is faster but stalls if a task throws an exception.
  74. This internal version of the ASAP function does not check for errors.
  75. If a task does throw an error, it will stall the event queue unless you manually
  76. call `rawAsap.requestFlush()` before throwing the error, or any time after.
  77. In Node.js, `asap/raw` also runs all tasks outside any domain.
  78. If you need a task to be bound to your domain, you will have to do it manually.
  79. ```js
  80. if (process.domain) {
  81. task = process.domain.bind(task);
  82. }
  83. rawAsap(task);
  84. ```
  85. ## Tasks
  86. A task may be any object that implements `call()`.
  87. A function will suffice, but closures tend not to be reusable and can cause
  88. garbage collector churn.
  89. Both `asap` and `rawAsap` accept task objects to give you the option of
  90. recycling task objects or using higher callable object abstractions.
  91. See the `asap` source for an illustration.
  92. ## Compatibility
  93. ASAP is tested on Node.js v0.10 and in a broad spectrum of web browsers.
  94. The following charts capture the browser test results for the most recent
  95. release.
  96. The first chart shows test results for ASAP running in the main window context.
  97. The second chart shows test results for ASAP running in a web worker context.
  98. Test results are inconclusive (grey) on browsers that do not support web
  99. workers.
  100. These data are captured automatically by [Continuous
  101. Integration][].
  102. [Continuous Integration]: https://github.com/kriskowal/asap/blob/master/CONTRIBUTING.md
  103. ![Browser Compatibility](http://kriskowal-asap.s3-website-us-west-2.amazonaws.com/train/integration-2/saucelabs-results-matrix.svg)
  104. ![Compatibility in Web Workers](http://kriskowal-asap.s3-website-us-west-2.amazonaws.com/train/integration-2/saucelabs-worker-results-matrix.svg)
  105. ## Caveats
  106. When a task is added to an empty event queue, it is not always possible to
  107. guarantee that the task queue will begin flushing immediately after the current
  108. event.
  109. However, once the task queue begins flushing, it will not yield until the queue
  110. is empty, even if the queue grows while executing tasks.
  111. The following browsers allow the use of [DOM mutation observers][] to access
  112. the HTML [microtask queue][], and thus begin flushing ASAP's task queue
  113. immediately at the end of the current event loop turn, before any rendering or
  114. IO:
  115. [microtask queue]: http://www.whatwg.org/specs/web-apps/current-work/multipage/webappapis.html#microtask-queue
  116. [DOM mutation observers]: http://dom.spec.whatwg.org/#mutation-observers
  117. - Android 4–4.3
  118. - Chrome 26–34
  119. - Firefox 14–29
  120. - Internet Explorer 11
  121. - iPad Safari 6–7.1
  122. - iPhone Safari 7–7.1
  123. - Safari 6–7
  124. In the absense of mutation observers, there are a few browsers, and situations
  125. like web workers in some of the above browsers, where [message channels][]
  126. would be a useful way to avoid falling back to timers.
  127. Message channels give direct access to the HTML [task queue][], so the ASAP
  128. task queue would flush after any already queued rendering and IO tasks, but
  129. without having the minimum delay imposed by timers.
  130. However, among these browsers, Internet Explorer 10 and Safari do not reliably
  131. dispatch messages, so they are not worth the trouble to implement.
  132. [message channels]: http://www.whatwg.org/specs/web-apps/current-work/multipage/web-messaging.html#message-channels
  133. [task queue]: http://www.whatwg.org/specs/web-apps/current-work/multipage/webappapis.html#concept-task
  134. - Internet Explorer 10
  135. - Safair 5.0-1
  136. - Opera 11-12
  137. In the absense of mutation observers, these browsers and the following browsers
  138. all fall back to using `setTimeout` and `setInterval` to ensure that a `flush`
  139. occurs.
  140. The implementation uses both and cancels whatever handler loses the race, since
  141. `setTimeout` tends to occasionally skip tasks in unisolated circumstances.
  142. Timers generally delay the flushing of ASAP's task queue for four milliseconds.
  143. - Firefox 3–13
  144. - Internet Explorer 6–10
  145. - iPad Safari 4.3
  146. - Lynx 2.8.7
  147. ## Heritage
  148. ASAP has been factored out of the [Q][] asynchronous promise library.
  149. It originally had a naïve implementation in terms of `setTimeout`, but
  150. [Malte Ubl][NonBlocking] provided an insight that `postMessage` might be
  151. useful for creating a high-priority, no-delay event dispatch hack.
  152. Since then, Internet Explorer proposed and implemented `setImmediate`.
  153. Robert Katić began contributing to Q by measuring the performance of
  154. the internal implementation of `asap`, paying particular attention to
  155. error recovery.
  156. Domenic, Robert, and Kris Kowal collectively settled on the current strategy of
  157. unrolling the high-priority event queue internally regardless of what strategy
  158. we used to dispatch the potentially lower-priority flush event.
  159. Domenic went on to make ASAP cooperate with Node.js domains.
  160. [Q]: https://github.com/kriskowal/q
  161. [NonBlocking]: http://www.nonblocking.io/2011/06/windownexttick.html
  162. For further reading, Nicholas Zakas provided a thorough article on [The
  163. Case for setImmediate][NCZ].
  164. [NCZ]: http://www.nczonline.net/blog/2013/07/09/the-case-for-setimmediate/
  165. Ember’s RSVP promise implementation later [adopted][RSVP ASAP] the name ASAP but
  166. further developed the implentation.
  167. Particularly, The `MessagePort` implementation was abandoned due to interaction
  168. [problems with Mobile Internet Explorer][IE Problems] in favor of an
  169. implementation backed on the newer and more reliable DOM `MutationObserver`
  170. interface.
  171. These changes were back-ported into this library.
  172. [IE Problems]: https://github.com/cujojs/when/issues/197
  173. [RSVP ASAP]: https://github.com/tildeio/rsvp.js/blob/cddf7232546a9cf858524b75cde6f9edf72620a7/lib/rsvp/asap.js
  174. In addition, ASAP factored into `asap` and `asap/raw`, such that `asap` remained
  175. exception-safe, but `asap/raw` provided a tight kernel that could be used for
  176. tasks that guaranteed that they would not throw exceptions.
  177. This core is useful for promise implementations that capture thrown errors in
  178. rejected promises and do not need a second safety net.
  179. At the same time, the exception handling in `asap` was factored into separate
  180. implementations for Node.js and browsers, using the the [Browserify][Browser
  181. Config] `browser` property in `package.json` to instruct browser module loaders
  182. and bundlers, including [Browserify][], [Mr][], and [Mop][], to use the
  183. browser-only implementation.
  184. [Browser Config]: https://gist.github.com/defunctzombie/4339901
  185. [Browserify]: https://github.com/substack/node-browserify
  186. [Mr]: https://github.com/montagejs/mr
  187. [Mop]: https://github.com/montagejs/mop
  188. ## License
  189. Copyright 2009-2014 by Contributors
  190. MIT License (enclosed)