UNPKG

axe-core

Version:

Accessibility engine for automated Web UI testing

139 lines (126 loc) 3.11 kB
(function () { 'use strict'; function noop() {} function funcGuard(f) { if (typeof f !== 'function') { throw new TypeError('Queue methods require functions as arguments'); } } /** * Create an asynchronous "queue", list of functions to be invoked in parallel, but not necessarily returned in order * @return {Queue} The newly generated "queue" */ function queue() { var tasks = []; var started = 0; var remaining = 0; // number of tasks not yet finished var completeQueue = noop; var complete = false; var err; // By default, wait until the next tick, // if no catch was set, throw to console. var defaultFail = function (e) { err = e; setTimeout(function () { if (err !== undefined && err !== null) { axe.log('Uncaught error (of queue)', err); } }, 1); }; var failed = defaultFail; function createResolve(i) { return function (r) { tasks[i] = r; remaining -= 1; if (!remaining && completeQueue !== noop) { complete = true; completeQueue(tasks); } }; } function abort(msg) { // reset tasks completeQueue = noop; // notify catch failed(msg); // return unfinished work return tasks; } function pop() { var length = tasks.length; for (; started < length; started++) { var task = tasks[started]; try { task.call(null, createResolve(started), abort); } catch (e) { abort(e); } } } var q = { /** * Defer a function that may or may not run asynchronously. * * First parameter should be the function to execute with subsequent * parameters being passed as arguments to that function */ defer: function (fn) { if (typeof fn === 'object' && fn.then && fn.catch) { var defer = fn; fn = function (resolve, reject) { defer.then(resolve).catch(reject); }; } funcGuard(fn); if (err !== undefined) { return; } else if (complete) { throw new Error('Queue already completed'); } tasks.push(fn); ++remaining; pop(); return q; }, /** * The callback to execute once all "deferred" functions have completed. Will only be invoked once. * @param {Function} f The callback, receives an array of the return/callbacked * values of each of the "deferred" functions */ then: function (fn) { funcGuard(fn); if (completeQueue !== noop) { throw new Error('queue `then` already set'); } if (!err) { completeQueue = fn; if (!remaining) { complete = true; completeQueue(tasks); } } return q; }, catch: function (fn) { funcGuard(fn); if (failed !== defaultFail) { throw new Error('queue `catch` already set'); } if (!err) { failed = fn; } else { fn(err); err = null; } return q; }, /** * Abort the "queue" and prevent `then` function from firing * @param {Function} fn The callback to execute; receives an array of the results which have completed */ abort: abort }; return q; } axe.utils.queue = queue; })();