UNPKG

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