UNPKG

modern-async

Version:

A modern tooling library for asynchronous operations using async/await, promises and async generators

1,514 lines (1,305 loc) 114 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define(['exports'], factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.modernAsync = {})); })(this, (function (exports) { 'use strict'; /** * Wraps an iterable or async iterable into an iterable that is guaranted to be async. * * @param {Iterable | AsyncIterable} iterable An iterable or async iterable object. * @yields {any} The elements returned by the original iterable. * @example * import { asyncIterableWrap } from 'modern-async' * * // example sync generator * function* syncGenerator() { * for (let i = 0; i < 3; i += 1) { * yield i * } * } * * const asyncIterable = asyncIterableWrap(syncGenerator()) * * for await (const el of asyncIterable) { * console.log(el) * } * // will print: * // 0 * // 1 * // 2 */ async function * asyncIterableWrap (iterable) { for await (const el of iterable) { yield el; } } var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; var nanoassert = assert; class AssertionError extends Error {} AssertionError.prototype.name = 'AssertionError'; /** * Minimal assert function * @param {any} t Value to check if falsy * @param {string=} m Optional assertion error message * @throws {AssertionError} */ function assert (t, m) { if (!t) { var err = new AssertionError(m); if (Error.captureStackTrace) Error.captureStackTrace(err, assert); throw err } } /** * Wraps a function call that may be synchronous in a function that * is guaranted to be async. This is a stricter version of calling a * function and wrapping its result using `Promise.resolve()` as the new function also * handles the case where the original function throws an exception. * * @param {Function} fct The function to wrap. * @returns {Function} The wrapped function. * @example * import { asyncWrap } from 'modern-async' * * const myFunction = () => { * // any kind of function that may or may not return a promise * } * * const asyncFct = asyncWrap(myFunction) * * const promise = asyncFct() * console.log(promise instanceof Promise) // prints true */ function asyncWrap (fct) { nanoassert(typeof fct === 'function', 'fct must be a function'); return async function () { return fct(...arguments) } } /** * Immediately calls an asynchronous function and redirects to an error handler if it throws an exception. * The error handler is optional, the default one just outputs the error in the console. * * This function is trivial but useful when you can't use top-level await for compatibility reasons. * * @param {Function} fct An asynchronous function to call. * @param {Function} [errorHandler] A facultative error handler. This function will receive a single argument: * the thrown exception. The default behavior is to output the exception in the console. * @example * import { asyncRoot } from 'modern-async' * * asyncRoot(async () => { * // any code using await * }, (e) => { * console.error("An error occured", e) * process.exit(-1) * }) */ async function asyncRoot (fct, errorHandler = null) { errorHandler = errorHandler || ((e) => { console.error(e); }); const asyncFct = asyncWrap(fct); try { await asyncFct(); } catch (e) { errorHandler(e); } } /** * An error type which is used when a promise is cancelled. */ class CancelledError extends Error { /** * Constructs a new instance. * * @param {string} message The error message */ constructor (message) { super(message); this.name = this.constructor.name; } } /** * A basic class to create a promise with its resolve and reject function in the same object. * * Instances of this class are never returned by any function of this library but it is used * internally and can be useful to code other asynchronous helpers. * * @example * import { Deferred, asyncSleep } from 'modern-async' * * const deferred = new Deferred() * * asyncSleep(10).then(() => { * deferred.resolve('test') * }) * * console.log(await deferred.promise) // will wait 10ms before printing 'test' */ class Deferred { /** * Constructs a deferred object. */ constructor () { this._promise = new Promise((resolve, reject) => { this._resolve = resolve; this._reject = reject; }); } /** * (Read-only) The promise. * * @member {Promise} * @returns {Promise} ignored */ get promise () { return this._promise } /** * (Read-only) The resolve function. * * @member {Function} * @returns {Function} The resolve function */ get resolve () { return this._resolve } /** * (Read-only) The reject function * * @member {Function} * @returns {Function} The reject function */ get reject () { return this._reject } } var check = function (it) { return it && it.Math == Math && it; }; // https://github.com/zloirock/core-js/issues/86#issuecomment-115759028 var global$o = // eslint-disable-next-line es/no-global-this -- safe check(typeof globalThis == 'object' && globalThis) || check(typeof window == 'object' && window) || // eslint-disable-next-line no-restricted-globals -- safe check(typeof self == 'object' && self) || check(typeof commonjsGlobal == 'object' && commonjsGlobal) || // eslint-disable-next-line no-new-func -- fallback (function () { return this; })() || Function('return this')(); var FunctionPrototype$1 = Function.prototype; var apply$2 = FunctionPrototype$1.apply; var bind$5 = FunctionPrototype$1.bind; var call$5 = FunctionPrototype$1.call; // eslint-disable-next-line es/no-reflect -- safe var functionApply = typeof Reflect == 'object' && Reflect.apply || (bind$5 ? call$5.bind(apply$2) : function () { return call$5.apply(apply$2, arguments); }); var FunctionPrototype = Function.prototype; var bind$4 = FunctionPrototype.bind; var call$4 = FunctionPrototype.call; var callBind = bind$4 && bind$4.bind(call$4); var functionUncurryThis = bind$4 ? function (fn) { return fn && callBind(call$4, fn); } : function (fn) { return fn && function () { return call$4.apply(fn, arguments); }; }; // `IsCallable` abstract operation // https://tc39.es/ecma262/#sec-iscallable var isCallable$8 = function (argument) { return typeof argument == 'function'; }; var objectGetOwnPropertyDescriptor = {}; var fails$6 = function (exec) { try { return !!exec(); } catch (error) { return true; } }; var fails$5 = fails$6; // Detect IE8's incomplete defineProperty implementation var descriptors = !fails$5(function () { // eslint-disable-next-line es/no-object-defineproperty -- required for testing return Object.defineProperty({}, 1, { get: function () { return 7; } })[1] != 7; }); var call$3 = Function.prototype.call; var functionCall = call$3.bind ? call$3.bind(call$3) : function () { return call$3.apply(call$3, arguments); }; var objectPropertyIsEnumerable = {}; var $propertyIsEnumerable = {}.propertyIsEnumerable; // eslint-disable-next-line es/no-object-getownpropertydescriptor -- safe var getOwnPropertyDescriptor$2 = Object.getOwnPropertyDescriptor; // Nashorn ~ JDK8 bug var NASHORN_BUG = getOwnPropertyDescriptor$2 && !$propertyIsEnumerable.call({ 1: 2 }, 1); // `Object.prototype.propertyIsEnumerable` method implementation // https://tc39.es/ecma262/#sec-object.prototype.propertyisenumerable objectPropertyIsEnumerable.f = NASHORN_BUG ? function propertyIsEnumerable(V) { var descriptor = getOwnPropertyDescriptor$2(this, V); return !!descriptor && descriptor.enumerable; } : $propertyIsEnumerable; var createPropertyDescriptor$2 = function (bitmap, value) { return { enumerable: !(bitmap & 1), configurable: !(bitmap & 2), writable: !(bitmap & 4), value: value }; }; var uncurryThis$7 = functionUncurryThis; var toString$1 = uncurryThis$7({}.toString); var stringSlice = uncurryThis$7(''.slice); var classofRaw = function (it) { return stringSlice(toString$1(it), 8, -1); }; var global$n = global$o; var uncurryThis$6 = functionUncurryThis; var fails$4 = fails$6; var classof$1 = classofRaw; var Object$3 = global$n.Object; var split = uncurryThis$6(''.split); // fallback for non-array-like ES3 and non-enumerable old V8 strings var indexedObject = fails$4(function () { // throws an error in rhino, see https://github.com/mozilla/rhino/issues/346 // eslint-disable-next-line no-prototype-builtins -- safe return !Object$3('z').propertyIsEnumerable(0); }) ? function (it) { return classof$1(it) == 'String' ? split(it, '') : Object$3(it); } : Object$3; var global$m = global$o; var TypeError$6 = global$m.TypeError; // `RequireObjectCoercible` abstract operation // https://tc39.es/ecma262/#sec-requireobjectcoercible var requireObjectCoercible$2 = function (it) { if (it == undefined) throw TypeError$6("Can't call method on " + it); return it; }; // toObject with fallback for non-array-like ES3 strings var IndexedObject = indexedObject; var requireObjectCoercible$1 = requireObjectCoercible$2; var toIndexedObject$1 = function (it) { return IndexedObject(requireObjectCoercible$1(it)); }; var isCallable$7 = isCallable$8; var isObject$4 = function (it) { return typeof it == 'object' ? it !== null : isCallable$7(it); }; var path$5 = {}; var path$4 = path$5; var global$l = global$o; var isCallable$6 = isCallable$8; var aFunction = function (variable) { return isCallable$6(variable) ? variable : undefined; }; var getBuiltIn$3 = function (namespace, method) { return arguments.length < 2 ? aFunction(path$4[namespace]) || aFunction(global$l[namespace]) : path$4[namespace] && path$4[namespace][method] || global$l[namespace] && global$l[namespace][method]; }; var uncurryThis$5 = functionUncurryThis; var objectIsPrototypeOf = uncurryThis$5({}.isPrototypeOf); var getBuiltIn$2 = getBuiltIn$3; var engineUserAgent = getBuiltIn$2('navigator', 'userAgent') || ''; var global$k = global$o; var userAgent$3 = engineUserAgent; var process$3 = global$k.process; var Deno = global$k.Deno; var versions = process$3 && process$3.versions || Deno && Deno.version; var v8 = versions && versions.v8; var match, version; if (v8) { match = v8.split('.'); // in old Chrome, versions of V8 isn't V8 = Chrome / 10 // but their correct versions are not interesting for us version = match[0] > 0 && match[0] < 4 ? 1 : +(match[0] + match[1]); } // BrowserFS NodeJS `process` polyfill incorrectly set `.v8` to `0.0` // so check `userAgent` even if `.v8` exists, but 0 if (!version && userAgent$3) { match = userAgent$3.match(/Edge\/(\d+)/); if (!match || match[1] >= 74) { match = userAgent$3.match(/Chrome\/(\d+)/); if (match) version = +match[1]; } } var engineV8Version = version; /* eslint-disable es/no-symbol -- required for testing */ var V8_VERSION = engineV8Version; var fails$3 = fails$6; // eslint-disable-next-line es/no-object-getownpropertysymbols -- required for testing var nativeSymbol = !!Object.getOwnPropertySymbols && !fails$3(function () { var symbol = Symbol(); // Chrome 38 Symbol has incorrect toString conversion // `get-own-property-symbols` polyfill symbols converted to object are not Symbol instances return !String(symbol) || !(Object(symbol) instanceof Symbol) || // Chrome 38-40 symbols are not inherited from DOM collections prototypes to instances !Symbol.sham && V8_VERSION && V8_VERSION < 41; }); /* eslint-disable es/no-symbol -- required for testing */ var NATIVE_SYMBOL$1 = nativeSymbol; var useSymbolAsUid = NATIVE_SYMBOL$1 && !Symbol.sham && typeof Symbol.iterator == 'symbol'; var global$j = global$o; var getBuiltIn$1 = getBuiltIn$3; var isCallable$5 = isCallable$8; var isPrototypeOf = objectIsPrototypeOf; var USE_SYMBOL_AS_UID$1 = useSymbolAsUid; var Object$2 = global$j.Object; var isSymbol$2 = USE_SYMBOL_AS_UID$1 ? function (it) { return typeof it == 'symbol'; } : function (it) { var $Symbol = getBuiltIn$1('Symbol'); return isCallable$5($Symbol) && isPrototypeOf($Symbol.prototype, Object$2(it)); }; var global$i = global$o; var String$3 = global$i.String; var tryToString$1 = function (argument) { try { return String$3(argument); } catch (error) { return 'Object'; } }; var global$h = global$o; var isCallable$4 = isCallable$8; var tryToString = tryToString$1; var TypeError$5 = global$h.TypeError; // `Assert: IsCallable(argument) is true` var aCallable$2 = function (argument) { if (isCallable$4(argument)) return argument; throw TypeError$5(tryToString(argument) + ' is not a function'); }; var aCallable$1 = aCallable$2; // `GetMethod` abstract operation // https://tc39.es/ecma262/#sec-getmethod var getMethod$1 = function (V, P) { var func = V[P]; return func == null ? undefined : aCallable$1(func); }; var global$g = global$o; var call$2 = functionCall; var isCallable$3 = isCallable$8; var isObject$3 = isObject$4; var TypeError$4 = global$g.TypeError; // `OrdinaryToPrimitive` abstract operation // https://tc39.es/ecma262/#sec-ordinarytoprimitive var ordinaryToPrimitive$1 = function (input, pref) { var fn, val; if (pref === 'string' && isCallable$3(fn = input.toString) && !isObject$3(val = call$2(fn, input))) return val; if (isCallable$3(fn = input.valueOf) && !isObject$3(val = call$2(fn, input))) return val; if (pref !== 'string' && isCallable$3(fn = input.toString) && !isObject$3(val = call$2(fn, input))) return val; throw TypeError$4("Can't convert object to primitive value"); }; var shared$1 = {exports: {}}; var global$f = global$o; // eslint-disable-next-line es/no-object-defineproperty -- safe var defineProperty = Object.defineProperty; var setGlobal$1 = function (key, value) { try { defineProperty(global$f, key, { value: value, configurable: true, writable: true }); } catch (error) { global$f[key] = value; } return value; }; var global$e = global$o; var setGlobal = setGlobal$1; var SHARED = '__core-js_shared__'; var store$1 = global$e[SHARED] || setGlobal(SHARED, {}); var sharedStore = store$1; var store = sharedStore; (shared$1.exports = function (key, value) { return store[key] || (store[key] = value !== undefined ? value : {}); })('versions', []).push({ version: '3.19.1', mode: 'pure' , copyright: '© 2021 Denis Pushkarev (zloirock.ru)' }); var global$d = global$o; var requireObjectCoercible = requireObjectCoercible$2; var Object$1 = global$d.Object; // `ToObject` abstract operation // https://tc39.es/ecma262/#sec-toobject var toObject$1 = function (argument) { return Object$1(requireObjectCoercible(argument)); }; var uncurryThis$4 = functionUncurryThis; var toObject = toObject$1; var hasOwnProperty = uncurryThis$4({}.hasOwnProperty); // `HasOwnProperty` abstract operation // https://tc39.es/ecma262/#sec-hasownproperty var hasOwnProperty_1 = Object.hasOwn || function hasOwn(it, key) { return hasOwnProperty(toObject(it), key); }; var uncurryThis$3 = functionUncurryThis; var id = 0; var postfix = Math.random(); var toString = uncurryThis$3(1.0.toString); var uid$1 = function (key) { return 'Symbol(' + (key === undefined ? '' : key) + ')_' + toString(++id + postfix, 36); }; var global$c = global$o; var shared = shared$1.exports; var hasOwn$3 = hasOwnProperty_1; var uid = uid$1; var NATIVE_SYMBOL = nativeSymbol; var USE_SYMBOL_AS_UID = useSymbolAsUid; var WellKnownSymbolsStore = shared('wks'); var Symbol$1 = global$c.Symbol; var symbolFor = Symbol$1 && Symbol$1['for']; var createWellKnownSymbol = USE_SYMBOL_AS_UID ? Symbol$1 : Symbol$1 && Symbol$1.withoutSetter || uid; var wellKnownSymbol$1 = function (name) { if (!hasOwn$3(WellKnownSymbolsStore, name) || !(NATIVE_SYMBOL || typeof WellKnownSymbolsStore[name] == 'string')) { var description = 'Symbol.' + name; if (NATIVE_SYMBOL && hasOwn$3(Symbol$1, name)) { WellKnownSymbolsStore[name] = Symbol$1[name]; } else if (USE_SYMBOL_AS_UID && symbolFor) { WellKnownSymbolsStore[name] = symbolFor(description); } else { WellKnownSymbolsStore[name] = createWellKnownSymbol(description); } } return WellKnownSymbolsStore[name]; }; var global$b = global$o; var call$1 = functionCall; var isObject$2 = isObject$4; var isSymbol$1 = isSymbol$2; var getMethod = getMethod$1; var ordinaryToPrimitive = ordinaryToPrimitive$1; var wellKnownSymbol = wellKnownSymbol$1; var TypeError$3 = global$b.TypeError; var TO_PRIMITIVE = wellKnownSymbol('toPrimitive'); // `ToPrimitive` abstract operation // https://tc39.es/ecma262/#sec-toprimitive var toPrimitive$1 = function (input, pref) { if (!isObject$2(input) || isSymbol$1(input)) return input; var exoticToPrim = getMethod(input, TO_PRIMITIVE); var result; if (exoticToPrim) { if (pref === undefined) pref = 'default'; result = call$1(exoticToPrim, input, pref); if (!isObject$2(result) || isSymbol$1(result)) return result; throw TypeError$3("Can't convert object to primitive value"); } if (pref === undefined) pref = 'number'; return ordinaryToPrimitive(input, pref); }; var toPrimitive = toPrimitive$1; var isSymbol = isSymbol$2; // `ToPropertyKey` abstract operation // https://tc39.es/ecma262/#sec-topropertykey var toPropertyKey$2 = function (argument) { var key = toPrimitive(argument, 'string'); return isSymbol(key) ? key : key + ''; }; var global$a = global$o; var isObject$1 = isObject$4; var document$1 = global$a.document; // typeof document.createElement is 'object' in old IE var EXISTS = isObject$1(document$1) && isObject$1(document$1.createElement); var documentCreateElement = function (it) { return EXISTS ? document$1.createElement(it) : {}; }; var DESCRIPTORS$3 = descriptors; var fails$2 = fails$6; var createElement$1 = documentCreateElement; // Thank's IE8 for his funny defineProperty var ie8DomDefine = !DESCRIPTORS$3 && !fails$2(function () { // eslint-disable-next-line es/no-object-defineproperty -- requied for testing return Object.defineProperty(createElement$1('div'), 'a', { get: function () { return 7; } }).a != 7; }); var DESCRIPTORS$2 = descriptors; var call = functionCall; var propertyIsEnumerableModule = objectPropertyIsEnumerable; var createPropertyDescriptor$1 = createPropertyDescriptor$2; var toIndexedObject = toIndexedObject$1; var toPropertyKey$1 = toPropertyKey$2; var hasOwn$2 = hasOwnProperty_1; var IE8_DOM_DEFINE$1 = ie8DomDefine; // eslint-disable-next-line es/no-object-getownpropertydescriptor -- safe var $getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor; // `Object.getOwnPropertyDescriptor` method // https://tc39.es/ecma262/#sec-object.getownpropertydescriptor objectGetOwnPropertyDescriptor.f = DESCRIPTORS$2 ? $getOwnPropertyDescriptor : function getOwnPropertyDescriptor(O, P) { O = toIndexedObject(O); P = toPropertyKey$1(P); if (IE8_DOM_DEFINE$1) try { return $getOwnPropertyDescriptor(O, P); } catch (error) { /* empty */ } if (hasOwn$2(O, P)) return createPropertyDescriptor$1(!call(propertyIsEnumerableModule.f, O, P), O[P]); }; var fails$1 = fails$6; var isCallable$2 = isCallable$8; var replacement = /#|\.prototype\./; var isForced$1 = function (feature, detection) { var value = data[normalize(feature)]; return value == POLYFILL ? true : value == NATIVE ? false : isCallable$2(detection) ? fails$1(detection) : !!detection; }; var normalize = isForced$1.normalize = function (string) { return String(string).replace(replacement, '.').toLowerCase(); }; var data = isForced$1.data = {}; var NATIVE = isForced$1.NATIVE = 'N'; var POLYFILL = isForced$1.POLYFILL = 'P'; var isForced_1 = isForced$1; var uncurryThis$2 = functionUncurryThis; var aCallable = aCallable$2; var bind$3 = uncurryThis$2(uncurryThis$2.bind); // optional / simple context binding var functionBindContext = function (fn, that) { aCallable(fn); return that === undefined ? fn : bind$3 ? bind$3(fn, that) : function (/* ...args */) { return fn.apply(that, arguments); }; }; var objectDefineProperty = {}; var global$9 = global$o; var isObject = isObject$4; var String$2 = global$9.String; var TypeError$2 = global$9.TypeError; // `Assert: Type(argument) is Object` var anObject$1 = function (argument) { if (isObject(argument)) return argument; throw TypeError$2(String$2(argument) + ' is not an object'); }; var global$8 = global$o; var DESCRIPTORS$1 = descriptors; var IE8_DOM_DEFINE = ie8DomDefine; var anObject = anObject$1; var toPropertyKey = toPropertyKey$2; var TypeError$1 = global$8.TypeError; // eslint-disable-next-line es/no-object-defineproperty -- safe var $defineProperty = Object.defineProperty; // `Object.defineProperty` method // https://tc39.es/ecma262/#sec-object.defineproperty objectDefineProperty.f = DESCRIPTORS$1 ? $defineProperty : function defineProperty(O, P, Attributes) { anObject(O); P = toPropertyKey(P); anObject(Attributes); if (IE8_DOM_DEFINE) try { return $defineProperty(O, P, Attributes); } catch (error) { /* empty */ } if ('get' in Attributes || 'set' in Attributes) throw TypeError$1('Accessors not supported'); if ('value' in Attributes) O[P] = Attributes.value; return O; }; var DESCRIPTORS = descriptors; var definePropertyModule = objectDefineProperty; var createPropertyDescriptor = createPropertyDescriptor$2; var createNonEnumerableProperty$1 = DESCRIPTORS ? function (object, key, value) { return definePropertyModule.f(object, key, createPropertyDescriptor(1, value)); } : function (object, key, value) { object[key] = value; return object; }; var global$7 = global$o; var apply$1 = functionApply; var uncurryThis$1 = functionUncurryThis; var isCallable$1 = isCallable$8; var getOwnPropertyDescriptor$1 = objectGetOwnPropertyDescriptor.f; var isForced = isForced_1; var path$3 = path$5; var bind$2 = functionBindContext; var createNonEnumerableProperty = createNonEnumerableProperty$1; var hasOwn$1 = hasOwnProperty_1; var wrapConstructor = function (NativeConstructor) { var Wrapper = function (a, b, c) { if (this instanceof Wrapper) { switch (arguments.length) { case 0: return new NativeConstructor(); case 1: return new NativeConstructor(a); case 2: return new NativeConstructor(a, b); } return new NativeConstructor(a, b, c); } return apply$1(NativeConstructor, this, arguments); }; Wrapper.prototype = NativeConstructor.prototype; return Wrapper; }; /* options.target - name of the target object options.global - target is the global object options.stat - export as static methods of target options.proto - export as prototype methods of target options.real - real prototype method for the `pure` version options.forced - export even if the native feature is available options.bind - bind methods to the target, required for the `pure` version options.wrap - wrap constructors to preventing global pollution, required for the `pure` version options.unsafe - use the simple assignment of property instead of delete + defineProperty options.sham - add a flag to not completely full polyfills options.enumerable - export as enumerable property options.noTargetGet - prevent calling a getter on target options.name - the .name of the function if it does not match the key */ var _export = function (options, source) { var TARGET = options.target; var GLOBAL = options.global; var STATIC = options.stat; var PROTO = options.proto; var nativeSource = GLOBAL ? global$7 : STATIC ? global$7[TARGET] : (global$7[TARGET] || {}).prototype; var target = GLOBAL ? path$3 : path$3[TARGET] || createNonEnumerableProperty(path$3, TARGET, {})[TARGET]; var targetPrototype = target.prototype; var FORCED, USE_NATIVE, VIRTUAL_PROTOTYPE; var key, sourceProperty, targetProperty, nativeProperty, resultProperty, descriptor; for (key in source) { FORCED = isForced(GLOBAL ? key : TARGET + (STATIC ? '.' : '#') + key, options.forced); // contains in native USE_NATIVE = !FORCED && nativeSource && hasOwn$1(nativeSource, key); targetProperty = target[key]; if (USE_NATIVE) if (options.noTargetGet) { descriptor = getOwnPropertyDescriptor$1(nativeSource, key); nativeProperty = descriptor && descriptor.value; } else nativeProperty = nativeSource[key]; // export native or implementation sourceProperty = (USE_NATIVE && nativeProperty) ? nativeProperty : source[key]; if (USE_NATIVE && typeof targetProperty == typeof sourceProperty) continue; // bind timers to global for call from export context if (options.bind && USE_NATIVE) resultProperty = bind$2(sourceProperty, global$7); // wrap global constructors for prevent changs in this version else if (options.wrap && USE_NATIVE) resultProperty = wrapConstructor(sourceProperty); // make static versions for prototype methods else if (PROTO && isCallable$1(sourceProperty)) resultProperty = uncurryThis$1(sourceProperty); // default case else resultProperty = sourceProperty; // add a flag to not completely full polyfills if (options.sham || (sourceProperty && sourceProperty.sham) || (targetProperty && targetProperty.sham)) { createNonEnumerableProperty(resultProperty, 'sham', true); } createNonEnumerableProperty(target, key, resultProperty); if (PROTO) { VIRTUAL_PROTOTYPE = TARGET + 'Prototype'; if (!hasOwn$1(path$3, VIRTUAL_PROTOTYPE)) { createNonEnumerableProperty(path$3, VIRTUAL_PROTOTYPE, {}); } // export virtual prototype methods createNonEnumerableProperty(path$3[VIRTUAL_PROTOTYPE], key, sourceProperty); // export real prototype methods if (options.real && targetPrototype && !targetPrototype[key]) { createNonEnumerableProperty(targetPrototype, key, sourceProperty); } } } }; var getBuiltIn = getBuiltIn$3; var html$1 = getBuiltIn('document', 'documentElement'); var uncurryThis = functionUncurryThis; var arraySlice$1 = uncurryThis([].slice); var userAgent$2 = engineUserAgent; var engineIsIos = /(?:ipad|iphone|ipod).*applewebkit/i.test(userAgent$2); var classof = classofRaw; var global$6 = global$o; var engineIsNode = classof(global$6.process) == 'process'; var global$5 = global$o; var apply = functionApply; var bind$1 = functionBindContext; var isCallable = isCallable$8; var hasOwn = hasOwnProperty_1; var fails = fails$6; var html = html$1; var arraySlice = arraySlice$1; var createElement = documentCreateElement; var IS_IOS$1 = engineIsIos; var IS_NODE$2 = engineIsNode; var set = global$5.setImmediate; var clear = global$5.clearImmediate; var process$2 = global$5.process; var Dispatch = global$5.Dispatch; var Function$1 = global$5.Function; var MessageChannel = global$5.MessageChannel; var String$1 = global$5.String; var counter = 0; var queue = {}; var ONREADYSTATECHANGE = 'onreadystatechange'; var location, defer, channel, port; try { // Deno throws a ReferenceError on `location` access without `--location` flag location = global$5.location; } catch (error) { /* empty */ } var run = function (id) { if (hasOwn(queue, id)) { var fn = queue[id]; delete queue[id]; fn(); } }; var runner = function (id) { return function () { run(id); }; }; var listener = function (event) { run(event.data); }; var post = function (id) { // old engines have not location.origin global$5.postMessage(String$1(id), location.protocol + '//' + location.host); }; // Node.js 0.9+ & IE10+ has setImmediate, otherwise: if (!set || !clear) { set = function setImmediate(fn) { var args = arraySlice(arguments, 1); queue[++counter] = function () { apply(isCallable(fn) ? fn : Function$1(fn), undefined, args); }; defer(counter); return counter; }; clear = function clearImmediate(id) { delete queue[id]; }; // Node.js 0.8- if (IS_NODE$2) { defer = function (id) { process$2.nextTick(runner(id)); }; // Sphere (JS game engine) Dispatch API } else if (Dispatch && Dispatch.now) { defer = function (id) { Dispatch.now(runner(id)); }; // Browsers with MessageChannel, includes WebWorkers // except iOS - https://github.com/zloirock/core-js/issues/624 } else if (MessageChannel && !IS_IOS$1) { channel = new MessageChannel(); port = channel.port2; channel.port1.onmessage = listener; defer = bind$1(port.postMessage, port); // Browsers with postMessage, skip WebWorkers // IE8 has postMessage, but it's sync & typeof its postMessage is 'object' } else if ( global$5.addEventListener && isCallable(global$5.postMessage) && !global$5.importScripts && location && location.protocol !== 'file:' && !fails(post) ) { defer = post; global$5.addEventListener('message', listener, false); // IE8- } else if (ONREADYSTATECHANGE in createElement('script')) { defer = function (id) { html.appendChild(createElement('script'))[ONREADYSTATECHANGE] = function () { html.removeChild(this); run(id); }; }; // Rest old browsers } else { defer = function (id) { setTimeout(runner(id), 0); }; } } var task$1 = { set: set, clear: clear }; var $$1 = _export; var global$4 = global$o; var task = task$1; var FORCED = !global$4.setImmediate || !global$4.clearImmediate; // http://w3c.github.io/setImmediate/ $$1({ global: true, bind: true, enumerable: true, forced: FORCED }, { // `setImmediate` method // http://w3c.github.io/setImmediate/#si-setImmediate setImmediate: task.set, // `clearImmediate` method // http://w3c.github.io/setImmediate/#si-clearImmediate clearImmediate: task.clear }); var path$2 = path$5; var setImmediate$1 = path$2.setImmediate; var parent$3 = setImmediate$1; var setImmediate = parent$3; var path$1 = path$5; var clearImmediate$1 = path$1.clearImmediate; var parent$2 = clearImmediate$1; var clearImmediate = parent$2; /** * A function returning a promise that will be resolved in a later tick of the event loop. * * This function returns both a promise and cancel function in order to cancel the wait time if * necessary. If cancelled, the promise will be rejected with a CancelledError. * * This function uses core-js' shim for `setImmediate()` internally. * * @returns {Array} A tuple of two objects: * * The promise * * The cancel function. It will return a boolean that will be true if the promise was effectively cancelled, * false otherwise. * @example * import { asyncDelayCancellable, CancelledError } from 'modern-async' * * const [promise, cancel] = asyncDelayCancellable() * cancel() * try { * await promise * } catch (e) { * console.log(e instanceof CancelledError) // prints true * } */ function asyncDelayCancellable () { const deferred = new Deferred(); const id = setImmediate(deferred.resolve); let terminated = false; return [deferred.promise.finally(() => { terminated = true; }), () => { if (terminated) { return false } else { terminated = true; deferred.reject(new CancelledError()); clearImmediate(id); return true } }] } /** * A function returning a promise that will be resolved in a later task of the event loop. * * This function uses core-js' shim for `setImmediate()` internally. * * @returns {Promise<void>} A promise that will be resolved on a later tick of the event loop. * @example * import { asyncDelay } from 'modern-async' * * console.log('this executes in a tick of the event loop') * await asyncDelay() * console.log('this executes in another tick of the event loop') */ async function asyncDelay () { return asyncDelayCancellable()[0] } /** * A class used to spread time or cpu intensive operations on multiple tasks in the event loop in order * to avoid blocking other tasks that may need to be executed. * * It is configured with a trigger time, which represents the maximum amount of time your tasks should * monopolize the event loop. Choosing an appropriate trigger time is both important and hard. If too low * it will impact the performances of your long running algorithm. If too high it will impact the other * tasks that need to run in the event loop. * * When using Delayer your code should contain frequent calls to `await delayer.checkDelay()`, usually * at the end of every loop. `checkDelay()` will check the amount of time that ellasped since the last time * it triggered a new task in the event loop. If the amount of time is below the trigger time it returns * an already resolved promise and the remaining computation will be able to continue processing in a * microtask. If not it will call the `asyncDelay()` function that will retrigger the operation in a later task * of the event loop. * * @example * import { Delayer } from 'modern-async' * * const delayer = new Delayer(10) // a delayer with 10ms trigger time * * // some cpu intensive operation that will run for a long time * for (let i = 0; i < 100000000; i += 1) { * // some code * await delayer.checkDelay() * } */ class Delayer { /** * Constructs a new `Delayer` by specifying its trigger time. * * @param {number} triggerTime The trigger time. */ constructor (triggerTime) { this.triggerTime = triggerTime; this.reset(); } /** * The trigger time of this `Delayer` in milliseconds. The trigger time represent the * maximum amount of time before a call to `checkDelay()` decide to schedule a new task in the event loop. * * @member {number} * @returns {number} ignore */ get triggerTime () { return this._triggerTime } /** * @ignore * @param {number} triggerTime ignore */ set triggerTime (triggerTime) { nanoassert(typeof triggerTime === 'number', 'trigger time must be a number'); this._triggerTime = triggerTime; } /** * Resets the internal timer to the current time. */ reset () { this._last = new Date().getTime(); } /** * Checks if a delay must be applied according to the internal timer. If that's the case this method * will call `asyncDelay()` and return `true`. If not it will do nothing and return `false`. * * @returns {boolean} `true` if a new task was scheduled in the event loop, `false` otherwise. */ async checkDelay () { const current = new Date().getTime(); if (current - this._last >= this.triggerTime) { await asyncDelay(); this.reset(); return true } else { return false } } } var userAgent$1 = engineUserAgent; var global$3 = global$o; var engineIsIosPebble = /ipad|iphone|ipod/i.test(userAgent$1) && global$3.Pebble !== undefined; var userAgent = engineUserAgent; var engineIsWebosWebkit = /web0s(?!.*chrome)/i.test(userAgent); var global$2 = global$o; var bind = functionBindContext; var getOwnPropertyDescriptor = objectGetOwnPropertyDescriptor.f; var macrotask = task$1.set; var IS_IOS = engineIsIos; var IS_IOS_PEBBLE = engineIsIosPebble; var IS_WEBOS_WEBKIT = engineIsWebosWebkit; var IS_NODE$1 = engineIsNode; var MutationObserver = global$2.MutationObserver || global$2.WebKitMutationObserver; var document = global$2.document; var process$1 = global$2.process; var Promise$1 = global$2.Promise; // Node.js 11 shows ExperimentalWarning on getting `queueMicrotask` var queueMicrotaskDescriptor = getOwnPropertyDescriptor(global$2, 'queueMicrotask'); var queueMicrotask$4 = queueMicrotaskDescriptor && queueMicrotaskDescriptor.value; var flush, head, last, notify, toggle, node, promise, then; // modern engines have queueMicrotask method if (!queueMicrotask$4) { flush = function () { var parent, fn; if (IS_NODE$1 && (parent = process$1.domain)) parent.exit(); while (head) { fn = head.fn; head = head.next; try { fn(); } catch (error) { if (head) notify(); else last = undefined; throw error; } } last = undefined; if (parent) parent.enter(); }; // browsers with MutationObserver, except iOS - https://github.com/zloirock/core-js/issues/339 // also except WebOS Webkit https://github.com/zloirock/core-js/issues/898 if (!IS_IOS && !IS_NODE$1 && !IS_WEBOS_WEBKIT && MutationObserver && document) { toggle = true; node = document.createTextNode(''); new MutationObserver(flush).observe(node, { characterData: true }); notify = function () { node.data = toggle = !toggle; }; // environments with maybe non-completely correct, but existent Promise } else if (!IS_IOS_PEBBLE && Promise$1 && Promise$1.resolve) { // Promise.resolve without an argument throws an error in LG WebOS 2 promise = Promise$1.resolve(undefined); // workaround of WebKit ~ iOS Safari 10.1 bug promise.constructor = Promise$1; then = bind(promise.then, promise); notify = function () { then(flush); }; // Node.js without promises } else if (IS_NODE$1) { notify = function () { process$1.nextTick(flush); }; // for other environments - macrotask based on: // - setImmediate // - MessageChannel // - window.postMessag // - onreadystatechange // - setTimeout } else { // strange IE + webpack dev server bug - use .bind(global) macrotask = bind(macrotask, global$2); notify = function () { macrotask(flush); }; } } var microtask$1 = queueMicrotask$4 || function (fn) { var task = { fn: fn, next: undefined }; if (last) last.next = task; if (!head) { head = task; notify(); } last = task; }; var $ = _export; var global$1 = global$o; var microtask = microtask$1; var IS_NODE = engineIsNode; var process = global$1.process; // `queueMicrotask` method // https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#dom-queuemicrotask $({ global: true, enumerable: true, noTargetGet: true }, { queueMicrotask: function queueMicrotask(fn) { var domain = IS_NODE && process.domain; microtask(domain ? domain.bind(fn) : fn); } }); var path = path$5; var queueMicrotask$3 = path.queueMicrotask; var parent$1 = queueMicrotask$3; var queueMicrotask$2 = parent$1; var parent = queueMicrotask$2; var queueMicrotask$1 = parent; /** * An alternative to standard `queueMicrotask()` function. * * This is just of mirror of core-js' implementation for compatibility. * * @param {Function} fct The function to call in a microtask. * @example * import { queueMicrotask } from 'modern-async' * * queueMicrotask(() => { * console.log('this resolves in a micro task') * }) */ function queueMicrotask (fct) { queueMicrotask$1(fct); } /** * A class representing a queue. * * Tasks added to the queue are processed in parallel (up to the concurrency limit). * If all slots of the queue are occupied, the task is queued until one becomes available. * When a slot is freed, the pending task with higher priority is executed. If multiple pending tasks have the same * priority the first that was scheduled is executed. * * Once a task is completed, its corresponding promise is terminated accordingly. * * @example * import { Queue, asyncSleep } from 'modern-async' * * const queue = new Queue(3) // create a queue with concurrency 3 * * const array = Array.from(Array(100).keys()) // an array of 100 numbers from 0 to 99 * * const promises = [] * for (const i of array) { * promises.push(queue.exec(async () => { * console.log(`Starting task ${i}`) * await asyncSleep(Math.random() * 10) // waits a random amount of time between 0ms and 10ms * console.log(`Ending task ${i}`) * return i; * })) * } * const results = await Promise.all(promises) * // all the scheduled tasks will perform with a maximum concurrency of 3 and log when they start and stop * * console.log(results) // will display an array with the result of the execution of each separate task */ class Queue { /** * Constructs a queue with the given concurrency * * @param {number} concurrency The concurrency of the queue, must be an integer greater than 0 or * `Number.POSITIVE_INFINITY`. */ constructor (concurrency) { nanoassert(Number.isInteger(concurrency) || concurrency === Number.POSITIVE_INFINITY, 'concurrency must be an integer or positive infinity'); nanoassert(concurrency > 0, 'concurrency must be greater than 0'); this._concurrency = concurrency; this._iqueue = []; this._running = 0; this._checkQueueScheduled = false; } /** * (Read-only) The concurrency of the queue. * * @member {number} * @returns {number} ignore */ get concurrency () { return this._concurrency } /** * (Read-only) The current number of tasks that are processing. * * @member {number} * @returns {number} ignore */ get running () { return this._running } /** * (Read-only) The number of pending tasks. * * @member {number} * @returns {number} ignore */ get pending () { return this._iqueue.length - this.running } /** * Puts a task at the end of the queue. When the task is executed and completes the returned promise will be terminated * accordingly. * * @param {Function} fct An asynchronous functions representing the task. It will be executed when the queue has * available slots and its result will be propagated to the promise returned by exec(). * @param {number} [priority] The priority of the task. The higher the priority is, the sooner the task will be * executed regarding the priority of other pending tasks. Defaults to 0. * @returns {Promise} A promise that will be resolved or rejected once the task has completed. Its state will be the same * than the promise returned by the call to `fct`. */ async exec (fct, priority = 0) { return this.execCancellable(fct, priority)[0] } /** * Puts a task at the end of the queue. When the task is executed and completes the returned promise will be terminated * accordingly. * * This function returns both a promise and a cancel function. The cancel function allows to cancel the pending task, * but only if it wasn't started yet. Calling the cancel function on a task that it already running has no effect. * When a task is cancelled its corresponding promise will be rejected with a `CancelledError`. * * @param {Function} fct An asynchronous functions representing the task. It will be executed when the queue has * available slots and its result will be propagated to the promise returned by exec(). * @param {number} [priority] The priority of the task. The higher the priority is, the sooner the task will be * executed regarding the priority of other pending tasks. Defaults to 0. * @returns {Array} A tuple with two parameters: * * `promise`: A promise that will be resolved or rejected once the task has completed. Its state will be the same * than the promise returned by the call to `fct`. * * `cancel`: A cancel function. When called it will cancel the task if it is still pending. It has no effect is the * task has already started or already terminated. When a task is cancelled its corresponding promise will be * rejected with a `CancelledError`. If will return `true` if the task was effectively pending and was cancelled, * `false` in any other case. */ execCancellable (fct, priority = 0) { nanoassert(typeof fct === 'function', 'fct must be a function'); nanoassert(typeof priority === 'number', 'priority must be a number'); const deferred = new Deferred(); let i = this._iqueue.length; while (i >= 1) { const t = this._iqueue[i - 1]; if (t.priority >= priority) { break } i -= 1; } const task = { asyncFct: asyncWrap(fct), deferred, priority, state: 'pending' }; this._iqueue.splice(i, 0, task); this._scheduleCheckQueue(); return [deferred.promise, () => { if (task.state !== 'pending') { return false } else { const filtered = this._iqueue.filter((v) => v !== task); nanoassert(filtered.length < this._iqueue.length); this._iqueue = filtered; task.state = 'cancelled'; deferred.reject(new CancelledError()); return true } }] } /** * @ignore */ _scheduleCheckQueue () { if (this._checkQueueScheduled) { return } this._checkQueueScheduled = true; queueMicrotask(() => { this._checkQueueScheduled = false; this._checkQueue(); }); } /** * @ignore */ _checkQueue () { while (true) { nanoassert(this.running >= 0, 'invalid state'); nanoassert(this.running <= this.concurrency, 'invalid state'); if (this.running === this.concurrency) { return } const task = this._iqueue.find((v) => v.state === 'pending'); if (task === undefined) { return } this._running += 1; task.state = 'running'; queueMicrotask(() => { task.asyncFct().finally(() => { this._running -= 1; this._iqueue = this._iqueue.filter((v) => v !== task); }).then(task.deferred.resolve, task.deferred.reject).then(() => { this._scheduleCheckQueue(); }); }); } } /** * Cancels all pending tasks. Their corresponding promises will be rejected with a `CancelledError`. This method will * not alter tasks that are already running. * * @returns {number} The number of pending tasks that were effectively cancelled. */ cancelAllPending () { const toCancel = this._iqueue.filter((task) => task.state === 'pending'); this._iqueue = this._iqueue.filter((task) => task.state !== 'pending'); toCancel.forEach((task) => { task.deferred.reject(new CancelledError()); }); return toCancel.length } } /** * @ignore * @param {*} queueOrConcurrency ignore * @returns {*} ignore */ function getQueue (queueOrConcurrency) { if (typeof queueOrConcurrency === 'number') { return new Queue(queueOrConcurrency) } else { return queueOrConcurrency } } /** * Immediately calls an asynchronous function and wraps its result into a promise that * can only be resolved, not rejected, regardless of the state of the promised returned * by the function. * * The returned promise will contain an object with the following fields: * * * `status`: A string, either "fulfilled" or "rejected", indicating the state of the * original promise. * * `value`: Only present if status is "fulfilled". The value that the promise was * fulfilled with. * * `reason`: Only present if status is "rejected". The reason that the promise was * rejected with. * * This object structure is similar to the one used by the [`Promise.allSettled()` * function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled). * * This function can be useful to make use of other functions in a fault-tolerant way. * * @par