UNPKG

ember-source

Version:

A JavaScript framework for creating ambitious web applications

229 lines (206 loc) 6.23 kB
import { assert } from '@ember/debug'; import { onErrorTarget } from '@ember/-internals/error-handling'; import { flushAsyncObservers } from '@ember/-internals/metal'; import Backburner from 'backburner.js'; let currentRunLoop = null; export function _getCurrentRunLoop() { return currentRunLoop; } function onBegin(current) { currentRunLoop = current; } function onEnd(_current, next) { currentRunLoop = next; flushAsyncObservers(); } function flush(queueName, next) { if (queueName === 'render' || queueName === _rsvpErrorQueue) { flushAsyncObservers(); } next(); } export const _rsvpErrorQueue = `${Math.random()}${Date.now()}`.replace('.', ''); /** Array of named queues. This array determines the order in which queues are flushed at the end of the RunLoop. You can define your own queues by simply adding the queue name to this array. Normally you should not need to inspect or modify this property. @property queues @type Array @default ['actions', 'destroy'] @private */ export const _queues = ['actions', // used in router transitions to prevent unnecessary loading state entry // if all context promises resolve on the 'actions' queue first 'routerTransitions', 'render', 'afterRender', 'destroy', // used to re-throw unhandled RSVP rejection errors specifically in this // position to avoid breaking anything rendered in the other sections _rsvpErrorQueue]; /** * @internal * @private */ export const _backburner = new Backburner(_queues, { defaultQueue: 'actions', onBegin, onEnd, onErrorTarget, onErrorMethod: 'onerror', flush }); export function run(...args) { // @ts-expect-error TS doesn't like our spread args return _backburner.run(...args); } export function join(methodOrTarget, methodOrArg, ...additionalArgs) { return _backburner.join(methodOrTarget, methodOrArg, ...additionalArgs); } export function bind(...curried) { assert('could not find a suitable method to bind', function (methodOrTarget, methodOrArg) { // Applies the same logic as backburner parseArgs for detecting if a method // is actually being passed. let length = arguments.length; if (length === 0) { return false; } else if (length === 1) { return typeof methodOrTarget === 'function'; } else { return typeof methodOrArg === 'function' || // second argument is a function methodOrTarget !== null && typeof methodOrArg === 'string' && methodOrArg in methodOrTarget || // second argument is the name of a method in first argument typeof methodOrTarget === 'function' //first argument is a function ; } // @ts-expect-error TS doesn't like our spread args }(...curried)); // @ts-expect-error TS doesn't like our spread args return (...args) => join(...curried.concat(args)); } /** Begins a new RunLoop. Any deferred actions invoked after the begin will be buffered until you invoke a matching call to `end()`. This is a lower-level way to use a RunLoop instead of using `run()`. ```javascript import { begin, end } from '@ember/runloop'; begin(); // code to be executed within a RunLoop end(); ``` @method begin @static @for @ember/runloop @return {void} @public */ export function begin() { _backburner.begin(); } /** Ends a RunLoop. This must be called sometime after you call `begin()` to flush any deferred actions. This is a lower-level way to use a RunLoop instead of using `run()`. ```javascript import { begin, end } from '@ember/runloop'; begin(); // code to be executed within a RunLoop end(); ``` @method end @static @for @ember/runloop @return {void} @public */ export function end() { _backburner.end(); } export function schedule(...args) { // @ts-expect-error TS doesn't like the rest args here return _backburner.schedule(...args); } // Used by global test teardown export function _hasScheduledTimers() { return _backburner.hasTimers(); } // Used by global test teardown export function _cancelTimers() { _backburner.cancelTimers(); } export function later(...args) { return _backburner.later(...args); } export function once(...args) { // @ts-expect-error TS doesn't like the rest args here return _backburner.scheduleOnce('actions', ...args); } export function scheduleOnce(...args) { // @ts-expect-error TS doesn't like the rest args here return _backburner.scheduleOnce(...args); } export function next(...args) { return _backburner.later(...args, 1); } /** Cancels a scheduled item. Must be a value returned by `later()`, `once()`, `scheduleOnce()`, `next()`, `debounce()`, or `throttle()`. ```javascript import { next, cancel, later, scheduleOnce, once, throttle, debounce } from '@ember/runloop'; let runNext = next(myContext, function() { // will not be executed }); cancel(runNext); let runLater = later(myContext, function() { // will not be executed }, 500); cancel(runLater); let runScheduleOnce = scheduleOnce('afterRender', myContext, function() { // will not be executed }); cancel(runScheduleOnce); let runOnce = once(myContext, function() { // will not be executed }); cancel(runOnce); let throttle = throttle(myContext, function() { // will not be executed }, 1, false); cancel(throttle); let debounce = debounce(myContext, function() { // will not be executed }, 1); cancel(debounce); let debounceImmediate = debounce(myContext, function() { // will be executed since we passed in true (immediate) }, 100, true); // the 100ms delay until this method can be called again will be canceled cancel(debounceImmediate); ``` @method cancel @static @for @ember/runloop @param {Object} [timer] Timer object to cancel @return {Boolean} true if canceled or false/undefined if it wasn't found @public */ export function cancel(timer) { return _backburner.cancel(timer); } export function debounce(...args) { // @ts-expect-error TS doesn't like the rest args here return _backburner.debounce(...args); } export function throttle(...args) { // @ts-expect-error TS doesn't like the rest args here return _backburner.throttle(...args); }