12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667 |
- "use strict";
- // rawAsap provides everything we need except exception management.
- var rawAsap = require("./raw");
- // RawTasks are recycled to reduce GC churn.
- var freeTasks = [];
- // We queue errors to ensure they are thrown in right order (FIFO).
- // Array-as-queue is good enough here, since we are just dealing with exceptions.
- var pendingErrors = [];
- var requestErrorThrow = rawAsap.makeRequestCallFromTimer(throwFirstError);
- function throwFirstError() {
- if (pendingErrors.length) {
- throw pendingErrors.shift();
- }
- }
- /**
- * Calls a task as soon as possible after returning, in its own event, with priority
- * over other events like animation, reflow, and repaint. An error thrown from an
- * event will not interrupt, nor even substantially slow down the processing of
- * other events, but will be rather postponed to a lower priority event.
- * @param {{call}} task A callable object, typically a function that takes no
- * arguments.
- */
- module.exports = asap;
- function asap(task) {
- var rawTask;
- if (freeTasks.length) {
- rawTask = freeTasks.pop();
- } else {
- rawTask = new RawTask();
- }
- rawTask.task = task;
- rawAsap(rawTask);
- }
- // We wrap tasks with recyclable task objects. A task object implements
- // `call`, just like a function.
- function RawTask() {
- this.task = null;
- }
- // The sole purpose of wrapping the task is to catch the exception and recycle
- // the task object after its single use.
- RawTask.prototype.call = function () {
- try {
- this.task.call();
- } catch (error) {
- if (asap.onerror) {
- // This hook exists purely for testing purposes.
- // Its name will be periodically randomized to break any code that
- // depends on its existence.
- asap.onerror(error);
- } else {
- // In a web browser, exceptions are not fatal. However, to avoid
- // slowing down the queue of pending tasks, we rethrow the error in a
- // lower priority turn.
- pendingErrors.push(error);
- requestErrorThrow();
- }
- } finally {
- this.task = null;
- freeTasks[freeTasks.length] = this;
- }
- };
|