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 238