mirror of
				https://github.com/1disk/edp445.git
				synced 2024-08-14 22:47:02 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			237 lines
		
	
	
	
		
			9.9 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			237 lines
		
	
	
	
		
			9.9 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
| # ASAP
 | ||
| 
 | ||
| [](https://travis-ci.org/kriskowal/asap)
 | ||
| 
 | ||
| Promise and asynchronous observer libraries, as well as hand-rolled callback
 | ||
| programs and libraries, often need a mechanism to postpone the execution of a
 | ||
| callback until the next available event.
 | ||
| (See [Designing API’s for Asynchrony][Zalgo].)
 | ||
| The `asap` function executes a task **as soon as possible** but not before it
 | ||
| returns, waiting only for the completion of the current event and previously
 | ||
| scheduled tasks.
 | ||
| 
 | ||
| ```javascript
 | ||
| asap(function () {
 | ||
|     // ...
 | ||
| });
 | ||
| ```
 | ||
| 
 | ||
| [Zalgo]: http://blog.izs.me/post/59142742143/designing-apis-for-asynchrony
 | ||
| 
 | ||
| This CommonJS package provides an `asap` module that exports a function that
 | ||
| executes a task function *as soon as possible*.
 | ||
| 
 | ||
| ASAP strives to schedule events to occur before yielding for IO, reflow,
 | ||
| or redrawing.
 | ||
| Each event receives an independent stack, with only platform code in parent
 | ||
| frames and the events run in the order they are scheduled.
 | ||
| 
 | ||
| ASAP provides a fast event queue that will execute tasks until it is
 | ||
| empty before yielding to the JavaScript engine's underlying event-loop.
 | ||
| When a task gets added to a previously empty event queue, ASAP schedules a flush
 | ||
| event, preferring for that event to occur before the JavaScript engine has an
 | ||
| opportunity to perform IO tasks or rendering, thus making the first task and
 | ||
| subsequent tasks semantically indistinguishable.
 | ||
| ASAP uses a variety of techniques to preserve this invariant on different
 | ||
| versions of browsers and Node.js.
 | ||
| 
 | ||
| By design, ASAP prevents input events from being handled until the task
 | ||
| queue is empty.
 | ||
| If the process is busy enough, this may cause incoming connection requests to be
 | ||
| dropped, and may cause existing connections to inform the sender to reduce the
 | ||
| transmission rate or stall.
 | ||
| ASAP allows this on the theory that, if there is enough work to do, there is no
 | ||
| sense in looking for trouble.
 | ||
| As a consequence, ASAP can interfere with smooth animation.
 | ||
| If your task should be tied to the rendering loop, consider using
 | ||
| `requestAnimationFrame` instead.
 | ||
| A long sequence of tasks can also effect the long running script dialog.
 | ||
| If this is a problem, you may be able to use ASAP’s cousin `setImmediate` to
 | ||
| break long processes into shorter intervals and periodically allow the browser
 | ||
| to breathe.
 | ||
| `setImmediate` will yield for IO, reflow, and repaint events.
 | ||
| It also returns a handler and can be canceled.
 | ||
| For a `setImmediate` shim, consider [YuzuJS setImmediate][setImmediate].
 | ||
| 
 | ||
| [setImmediate]: https://github.com/YuzuJS/setImmediate
 | ||
| 
 | ||
| Take care.
 | ||
| ASAP can sustain infinite recursive calls without warning.
 | ||
| It will not halt from a stack overflow, and it will not consume unbounded
 | ||
| memory.
 | ||
| This is behaviorally equivalent to an infinite loop.
 | ||
| Just as with infinite loops, you can monitor a Node.js process for this behavior
 | ||
| with a heart-beat signal.
 | ||
| As with infinite loops, a very small amount of caution goes a long way to
 | ||
| avoiding problems.
 | ||
| 
 | ||
| ```javascript
 | ||
| function loop() {
 | ||
|     asap(loop);
 | ||
| }
 | ||
| loop();
 | ||
| ```
 | ||
| 
 | ||
| In browsers, if a task throws an exception, it will not interrupt the flushing
 | ||
| of high-priority tasks.
 | ||
| The exception will be postponed to a later, low-priority event to avoid
 | ||
| slow-downs.
 | ||
| In Node.js, if a task throws an exception, ASAP will resume flushing only if—and
 | ||
| only after—the error is handled by `domain.on("error")` or
 | ||
| `process.on("uncaughtException")`.
 | ||
| 
 | ||
| ## Raw ASAP
 | ||
| 
 | ||
| Checking for exceptions comes at a cost.
 | ||
| The package also provides an `asap/raw` module that exports the underlying
 | ||
| implementation which is faster but stalls if a task throws an exception.
 | ||
| This internal version of the ASAP function does not check for errors.
 | ||
| If a task does throw an error, it will stall the event queue unless you manually
 | ||
| call `rawAsap.requestFlush()` before throwing the error, or any time after.
 | ||
| 
 | ||
| In Node.js, `asap/raw` also runs all tasks outside any domain.
 | ||
| If you need a task to be bound to your domain, you will have to do it manually.
 | ||
| 
 | ||
| ```js
 | ||
| if (process.domain) {
 | ||
|     task = process.domain.bind(task);
 | ||
| }
 | ||
| rawAsap(task);
 | ||
| ```
 | ||
| 
 | ||
| ## Tasks
 | ||
| 
 | ||
| A task may be any object that implements `call()`.
 | ||
| A function will suffice, but closures tend not to be reusable and can cause
 | ||
| garbage collector churn.
 | ||
| Both `asap` and `rawAsap` accept task objects to give you the option of
 | ||
| recycling task objects or using higher callable object abstractions.
 | ||
| See the `asap` source for an illustration.
 | ||
| 
 | ||
| 
 | ||
| ## Compatibility
 | ||
| 
 | ||
| ASAP is tested on Node.js v0.10 and in a broad spectrum of web browsers.
 | ||
| The following charts capture the browser test results for the most recent
 | ||
| release.
 | ||
| The first chart shows test results for ASAP running in the main window context.
 | ||
| The second chart shows test results for ASAP running in a web worker context.
 | ||
| Test results are inconclusive (grey) on browsers that do not support web
 | ||
| workers.
 | ||
| These data are captured automatically by [Continuous
 | ||
| Integration][].
 | ||
| 
 | ||
| [Continuous Integration]: https://github.com/kriskowal/asap/blob/master/CONTRIBUTING.md
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| ## Caveats
 | ||
| 
 | ||
| When a task is added to an empty event queue, it is not always possible to
 | ||
| guarantee that the task queue will begin flushing immediately after the current
 | ||
| event.
 | ||
| However, once the task queue begins flushing, it will not yield until the queue
 | ||
| is empty, even if the queue grows while executing tasks.
 | ||
| 
 | ||
| The following browsers allow the use of [DOM mutation observers][] to access
 | ||
| the HTML [microtask queue][], and thus begin flushing ASAP's task queue
 | ||
| immediately at the end of the current event loop turn, before any rendering or
 | ||
| IO:
 | ||
| 
 | ||
| [microtask queue]: http://www.whatwg.org/specs/web-apps/current-work/multipage/webappapis.html#microtask-queue
 | ||
| [DOM mutation observers]: http://dom.spec.whatwg.org/#mutation-observers
 | ||
| 
 | ||
| - Android 4–4.3
 | ||
| - Chrome 26–34
 | ||
| - Firefox 14–29
 | ||
| - Internet Explorer 11
 | ||
| - iPad Safari 6–7.1
 | ||
| - iPhone Safari 7–7.1
 | ||
| - Safari 6–7
 | ||
| 
 | ||
| In the absense of mutation observers, there are a few browsers, and situations
 | ||
| like web workers in some of the above browsers,  where [message channels][]
 | ||
| would be a useful way to avoid falling back to timers.
 | ||
| Message channels give direct access to the HTML [task queue][], so the ASAP
 | ||
| task queue would flush after any already queued rendering and IO tasks, but
 | ||
| without having the minimum delay imposed by timers.
 | ||
| However, among these browsers, Internet Explorer 10 and Safari do not reliably
 | ||
| dispatch messages, so they are not worth the trouble to implement.
 | ||
| 
 | ||
| [message channels]: http://www.whatwg.org/specs/web-apps/current-work/multipage/web-messaging.html#message-channels
 | ||
| [task queue]: http://www.whatwg.org/specs/web-apps/current-work/multipage/webappapis.html#concept-task
 | ||
| 
 | ||
| - Internet Explorer 10
 | ||
| - Safair 5.0-1
 | ||
| - Opera 11-12
 | ||
| 
 | ||
| In the absense of mutation observers, these browsers and the following browsers
 | ||
| all fall back to using `setTimeout` and `setInterval` to ensure that a `flush`
 | ||
| occurs.
 | ||
| The implementation uses both and cancels whatever handler loses the race, since
 | ||
| `setTimeout` tends to occasionally skip tasks in unisolated circumstances.
 | ||
| Timers generally delay the flushing of ASAP's task queue for four milliseconds.
 | ||
| 
 | ||
| - Firefox 3–13
 | ||
| - Internet Explorer 6–10
 | ||
| - iPad Safari 4.3
 | ||
| - Lynx 2.8.7
 | ||
| 
 | ||
| 
 | ||
| ## Heritage
 | ||
| 
 | ||
| ASAP has been factored out of the [Q][] asynchronous promise library.
 | ||
| It originally had a naïve implementation in terms of `setTimeout`, but
 | ||
| [Malte Ubl][NonBlocking] provided an insight that `postMessage` might be
 | ||
| useful for creating a high-priority, no-delay event dispatch hack.
 | ||
| Since then, Internet Explorer proposed and implemented `setImmediate`.
 | ||
| Robert Katić began contributing to Q by measuring the performance of
 | ||
| the internal implementation of `asap`, paying particular attention to
 | ||
| error recovery.
 | ||
| Domenic, Robert, and Kris Kowal collectively settled on the current strategy of
 | ||
| unrolling the high-priority event queue internally regardless of what strategy
 | ||
| we used to dispatch the potentially lower-priority flush event.
 | ||
| Domenic went on to make ASAP cooperate with Node.js domains.
 | ||
| 
 | ||
| [Q]: https://github.com/kriskowal/q
 | ||
| [NonBlocking]: http://www.nonblocking.io/2011/06/windownexttick.html
 | ||
| 
 | ||
| For further reading, Nicholas Zakas provided a thorough article on [The
 | ||
| Case for setImmediate][NCZ].
 | ||
| 
 | ||
| [NCZ]: http://www.nczonline.net/blog/2013/07/09/the-case-for-setimmediate/
 | ||
| 
 | ||
| Ember’s RSVP promise implementation later [adopted][RSVP ASAP] the name ASAP but
 | ||
| further developed the implentation.
 | ||
| Particularly, The `MessagePort` implementation was abandoned due to interaction
 | ||
| [problems with Mobile Internet Explorer][IE Problems] in favor of an
 | ||
| implementation backed on the newer and more reliable DOM `MutationObserver`
 | ||
| interface.
 | ||
| These changes were back-ported into this library.
 | ||
| 
 | ||
| [IE Problems]: https://github.com/cujojs/when/issues/197
 | ||
| [RSVP ASAP]: https://github.com/tildeio/rsvp.js/blob/cddf7232546a9cf858524b75cde6f9edf72620a7/lib/rsvp/asap.js
 | ||
| 
 | ||
| In addition, ASAP factored into `asap` and `asap/raw`, such that `asap` remained
 | ||
| exception-safe, but `asap/raw` provided a tight kernel that could be used for
 | ||
| tasks that guaranteed that they would not throw exceptions.
 | ||
| This core is useful for promise implementations that capture thrown errors in
 | ||
| rejected promises and do not need a second safety net.
 | ||
| At the same time, the exception handling in `asap` was factored into separate
 | ||
| implementations for Node.js and browsers, using the the [Browserify][Browser
 | ||
| Config] `browser` property in `package.json` to instruct browser module loaders
 | ||
| and bundlers, including [Browserify][], [Mr][], and [Mop][],  to use the
 | ||
| browser-only implementation.
 | ||
| 
 | ||
| [Browser Config]: https://gist.github.com/defunctzombie/4339901
 | ||
| [Browserify]: https://github.com/substack/node-browserify
 | ||
| [Mr]: https://github.com/montagejs/mr
 | ||
| [Mop]: https://github.com/montagejs/mop
 | ||
| 
 | ||
| ## License
 | ||
| 
 | ||
| Copyright 2009-2014 by Contributors
 | ||
| MIT License (enclosed)
 | ||
| 
 |