• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1"use strict";
2
3// rawAsap provides everything we need except exception management.
4var rawAsap = require("./raw");
5// RawTasks are recycled to reduce GC churn.
6var freeTasks = [];
7// We queue errors to ensure they are thrown in right order (FIFO).
8// Array-as-queue is good enough here, since we are just dealing with exceptions.
9var pendingErrors = [];
10var requestErrorThrow = rawAsap.makeRequestCallFromTimer(throwFirstError);
11
12function throwFirstError() {
13    if (pendingErrors.length) {
14        throw pendingErrors.shift();
15    }
16}
17
18/**
19 * Calls a task as soon as possible after returning, in its own event, with priority
20 * over other events like animation, reflow, and repaint. An error thrown from an
21 * event will not interrupt, nor even substantially slow down the processing of
22 * other events, but will be rather postponed to a lower priority event.
23 * @param {{call}} task A callable object, typically a function that takes no
24 * arguments.
25 */
26module.exports = asap;
27function asap(task) {
28    var rawTask;
29    if (freeTasks.length) {
30        rawTask = freeTasks.pop();
31    } else {
32        rawTask = new RawTask();
33    }
34    rawTask.task = task;
35    rawAsap(rawTask);
36}
37
38// We wrap tasks with recyclable task objects.  A task object implements
39// `call`, just like a function.
40function RawTask() {
41    this.task = null;
42}
43
44// The sole purpose of wrapping the task is to catch the exception and recycle
45// the task object after its single use.
46RawTask.prototype.call = function () {
47    try {
48        this.task.call();
49    } catch (error) {
50        if (asap.onerror) {
51            // This hook exists purely for testing purposes.
52            // Its name will be periodically randomized to break any code that
53            // depends on its existence.
54            asap.onerror(error);
55        } else {
56            // In a web browser, exceptions are not fatal. However, to avoid
57            // slowing down the queue of pending tasks, we rethrow the error in a
58            // lower priority turn.
59            pendingErrors.push(error);
60            requestErrorThrow();
61        }
62    } finally {
63        this.task = null;
64        freeTasks[freeTasks.length] = this;
65    }
66};
67