| /** |
| @license |
| Copyright (c) 2017 The Polymer Project Authors. All rights reserved. |
| This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt |
| The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt |
| The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt |
| Code distributed by Google as part of the polymer project is also |
| subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt |
| */ |
| |
| /** |
| * @fileoverview |
| * |
| * This module provides a number of strategies for enqueuing asynchronous |
| * tasks. Each sub-module provides a standard `run(fn)` interface that returns a |
| * handle, and a `cancel(handle)` interface for canceling async tasks before |
| * they run. |
| * |
| * @summary Module that provides a number of strategies for enqueuing |
| * asynchronous tasks. |
| */ |
| |
| import './boot.js'; |
| |
| // Microtask implemented using Mutation Observer |
| let microtaskCurrHandle = 0; |
| let microtaskLastHandle = 0; |
| let microtaskCallbacks = []; |
| let microtaskNodeContent = 0; |
| let microtaskNode = document.createTextNode(''); |
| new window.MutationObserver(microtaskFlush).observe(microtaskNode, {characterData: true}); |
| |
| function microtaskFlush() { |
| const len = microtaskCallbacks.length; |
| for (let i = 0; i < len; i++) { |
| let cb = microtaskCallbacks[i]; |
| if (cb) { |
| try { |
| cb(); |
| } catch (e) { |
| setTimeout(() => { throw e; }); |
| } |
| } |
| } |
| microtaskCallbacks.splice(0, len); |
| microtaskLastHandle += len; |
| } |
| |
| /** |
| * Async interface wrapper around `setTimeout`. |
| * |
| * @namespace |
| * @summary Async interface wrapper around `setTimeout`. |
| */ |
| const timeOut = { |
| /** |
| * Returns a sub-module with the async interface providing the provided |
| * delay. |
| * |
| * @memberof timeOut |
| * @param {number=} delay Time to wait before calling callbacks in ms |
| * @return {!AsyncInterface} An async timeout interface |
| */ |
| after(delay) { |
| return { |
| run(fn) { return window.setTimeout(fn, delay); }, |
| cancel(handle) { |
| window.clearTimeout(handle); |
| } |
| }; |
| }, |
| /** |
| * Enqueues a function called in the next task. |
| * |
| * @memberof timeOut |
| * @param {!Function} fn Callback to run |
| * @param {number=} delay Delay in milliseconds |
| * @return {number} Handle used for canceling task |
| */ |
| run(fn, delay) { |
| return window.setTimeout(fn, delay); |
| }, |
| /** |
| * Cancels a previously enqueued `timeOut` callback. |
| * |
| * @memberof timeOut |
| * @param {number} handle Handle returned from `run` of callback to cancel |
| * @return {void} |
| */ |
| cancel(handle) { |
| window.clearTimeout(handle); |
| } |
| }; |
| export {timeOut}; |
| |
| /** |
| * Async interface wrapper around `requestAnimationFrame`. |
| * |
| * @namespace |
| * @summary Async interface wrapper around `requestAnimationFrame`. |
| */ |
| const animationFrame = { |
| /** |
| * Enqueues a function called at `requestAnimationFrame` timing. |
| * |
| * @memberof animationFrame |
| * @param {function(number):void} fn Callback to run |
| * @return {number} Handle used for canceling task |
| */ |
| run(fn) { |
| return window.requestAnimationFrame(fn); |
| }, |
| /** |
| * Cancels a previously enqueued `animationFrame` callback. |
| * |
| * @memberof animationFrame |
| * @param {number} handle Handle returned from `run` of callback to cancel |
| * @return {void} |
| */ |
| cancel(handle) { |
| window.cancelAnimationFrame(handle); |
| } |
| }; |
| export {animationFrame}; |
| |
| /** |
| * Async interface wrapper around `requestIdleCallback`. Falls back to |
| * `setTimeout` on browsers that do not support `requestIdleCallback`. |
| * |
| * @namespace |
| * @summary Async interface wrapper around `requestIdleCallback`. |
| */ |
| const idlePeriod = { |
| /** |
| * Enqueues a function called at `requestIdleCallback` timing. |
| * |
| * @memberof idlePeriod |
| * @param {function(!IdleDeadline):void} fn Callback to run |
| * @return {number} Handle used for canceling task |
| */ |
| run(fn) { |
| return window.requestIdleCallback ? |
| window.requestIdleCallback(fn) : |
| window.setTimeout(fn, 16); |
| }, |
| /** |
| * Cancels a previously enqueued `idlePeriod` callback. |
| * |
| * @memberof idlePeriod |
| * @param {number} handle Handle returned from `run` of callback to cancel |
| * @return {void} |
| */ |
| cancel(handle) { |
| window.cancelIdleCallback ? |
| window.cancelIdleCallback(handle) : |
| window.clearTimeout(handle); |
| } |
| }; |
| export {idlePeriod}; |
| |
| /** |
| * Async interface for enqueuing callbacks that run at microtask timing. |
| * |
| * Note that microtask timing is achieved via a single `MutationObserver`, |
| * and thus callbacks enqueued with this API will all run in a single |
| * batch, and not interleaved with other microtasks such as promises. |
| * Promises are avoided as an implementation choice for the time being |
| * due to Safari bugs that cause Promises to lack microtask guarantees. |
| * |
| * @namespace |
| * @summary Async interface for enqueuing callbacks that run at microtask |
| * timing. |
| */ |
| const microTask = { |
| |
| /** |
| * Enqueues a function called at microtask timing. |
| * |
| * @memberof microTask |
| * @param {!Function=} callback Callback to run |
| * @return {number} Handle used for canceling task |
| */ |
| run(callback) { |
| microtaskNode.textContent = microtaskNodeContent++; |
| microtaskCallbacks.push(callback); |
| return microtaskCurrHandle++; |
| }, |
| |
| /** |
| * Cancels a previously enqueued `microTask` callback. |
| * |
| * @memberof microTask |
| * @param {number} handle Handle returned from `run` of callback to cancel |
| * @return {void} |
| */ |
| cancel(handle) { |
| const idx = handle - microtaskLastHandle; |
| if (idx >= 0) { |
| if (!microtaskCallbacks[idx]) { |
| throw new Error('invalid async handle: ' + handle); |
| } |
| microtaskCallbacks[idx] = null; |
| } |
| } |
| |
| }; |
| export {microTask}; |