UNPKG

@nevware21/ts-async

Version:

support for asynchronous development with a Promise based task Scheduler, several different Promise implementations (synchronous, idle, asynchronous and native runtime wrappers), await helpers, and aliases all built and tested using TypeScript.

1,127 lines (1,105 loc) 45.4 kB
/*! * NevWare21 Solutions LLC - ts-async, 0.5.5 * https://github.com/nevware21/ts-async * Copyright (c) NevWare21 Solutions LLC and contributors. All rights reserved. * Licensed under the MIT license. */ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@nevware21/ts-utils')) : typeof define === 'function' && define.amd ? define(['exports', '@nevware21/ts-utils'], factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory((global.nevware21 = global.nevware21 || {}, global.nevware21["ts-async"] = {}), global.nevware21["ts-utils"])); })(this, (function (exports, tsUtils) { 'use strict'; const STR_PROMISE = "Promise"; const DONE = "done"; const VALUE = "value"; const RETURN = "return"; const REJECTED = "rejected"; function doAwaitResponse(value, cb) { return doAwait(value, (value) => { return cb ? cb({ status: "fulfilled", rejected: false, value: value }) : value; }, (reason) => { return cb ? cb({ status: REJECTED, rejected: true, reason: reason }) : reason; }); } function doAwait(value, resolveFn, rejectFn, finallyFn) { let result = value; try { if (tsUtils.isPromiseLike(value)) { if (resolveFn || rejectFn) { result = value.then(resolveFn, rejectFn); } } else { try { if (resolveFn) { result = resolveFn(value); } } catch (err) { if (rejectFn) { result = rejectFn(err); } else { throw err; } } } } finally { if (finallyFn) { doFinally(result, finallyFn); } } return result; } function doFinally(value, finallyFn) { let result = value; if (finallyFn) { if (tsUtils.isPromiseLike(value)) { if (value.finally) { result = value.finally(finallyFn); } else { result = value.then(function (value) { finallyFn(); return value; }, function (reason) { finallyFn(); throw reason; }); } } else { finallyFn(); } } return result; } function _pureAssign(func1, func2) { return func1 || func2; } let _debugState; let _debugResult; let _debugHandled; let _promiseDebugEnabled = false; function _addDebugState$1(thePromise, stateFn, resultFn, handledFn) { _debugState = _debugState || { toString: () => "[[PromiseState]]" }; _debugResult = _debugResult || { toString: () => "[[PromiseResult]]" }; _debugHandled = _debugHandled || { toString: () => "[[PromiseIsHandled]]" }; let props = {}; props[_debugState] = { get: stateFn }; props[_debugResult] = { get: resultFn }; props[_debugHandled] = { get: handledFn }; tsUtils.objDefineProperties(thePromise, props); } function setPromiseDebugState(enabled, logger) { _promiseDebugEnabled = enabled; } const STRING_STATES = [ "pending", "resolving", "resolved", REJECTED ]; const DISPATCH_EVENT = "dispatchEvent"; let _hasInitEvent; function _hasInitEventFn(doc) { let evt; if (doc && doc.createEvent) { evt = doc.createEvent("Event"); } return (!!evt && evt.initEvent); } function emitEvent(target, evtName, populateEvent, useNewEvent) { let doc = tsUtils.getDocument(); !_hasInitEvent && (_hasInitEvent = tsUtils.createCachedValue(!!tsUtils.safe(_hasInitEventFn, [doc]).v)); let theEvt = _hasInitEvent.v ? doc.createEvent("Event") : (useNewEvent ? new Event(evtName) : {}); populateEvent && populateEvent(theEvt); if (_hasInitEvent.v) { theEvt.initEvent(evtName, false, true); } if (theEvt && target[DISPATCH_EVENT]) { target[DISPATCH_EVENT](theEvt); } else { let handler = target["on" + evtName]; if (handler) { handler(theEvt); } else { let theConsole = tsUtils.getInst("console"); theConsole && (theConsole["error"] || theConsole["log"])(evtName, tsUtils.dumpObj(theEvt)); } } } const NODE_UNHANDLED_REJECTION = "unhandledRejection"; const UNHANDLED_REJECTION = NODE_UNHANDLED_REJECTION.toLowerCase(); let _currentPromiseId = []; let _uniquePromiseId = 0; let _unhandledRejectionTimeout = 10; let _aggregationError; let _hasPromiseRejectionEvent; function dumpFnObj(value) { if (tsUtils.isFunction(value)) { return value.toString(); } return tsUtils.dumpObj(value); } function _createAggregationError(values) { !_aggregationError && (_aggregationError = tsUtils.createCachedValue(tsUtils.safe(tsUtils.getInst, ["AggregationError"]).v || tsUtils.createCustomError("AggregationError", (self, args) => { self.errors = args[0]; }))); return new _aggregationError.v(values); } function _createPromise(newPromise, processor, executor) { let additionalArgs = tsUtils.arrSlice(arguments, 3); let _state = 0; let _hasResolved = false; let _settledValue; let _queue = []; let _id = _uniquePromiseId++; let _parentId = _currentPromiseId.length > 0 ? _currentPromiseId[_currentPromiseId.length - 1] : undefined; let _handled = false; let _unHandledRejectionHandler = null; let _thePromise; function _then(onResolved, onRejected) { try { _currentPromiseId.push(_id); _handled = true; _unHandledRejectionHandler && _unHandledRejectionHandler.cancel(); _unHandledRejectionHandler = null; let thenPromise = newPromise(function (resolve, reject) { _queue.push(function () { try { let handler = _state === 2 ? onResolved : onRejected; let value = tsUtils.isUndefined(handler) ? _settledValue : (tsUtils.isFunction(handler) ? handler(_settledValue) : handler); if (tsUtils.isPromiseLike(value)) { value.then(resolve, reject); } else if (handler) { resolve(value); } else if (_state === 3) { reject(value); } else { resolve(value); } } catch (e) { reject(e); } }); if (_hasResolved) { _processQueue(); } }, additionalArgs); return thenPromise; } finally { _currentPromiseId.pop(); } } function _catch(onRejected) { return _then(undefined, onRejected); } function _finally(onFinally) { let thenFinally = onFinally; let catchFinally = onFinally; if (tsUtils.isFunction(onFinally)) { thenFinally = function (value) { onFinally && onFinally(); return value; }; catchFinally = function (reason) { onFinally && onFinally(); throw reason; }; } return _then(thenFinally, catchFinally); } function _strState() { return STRING_STATES[_state]; } function _processQueue() { if (_queue.length > 0) { let pending = _queue.slice(); _queue = []; _handled = true; _unHandledRejectionHandler && _unHandledRejectionHandler.cancel(); _unHandledRejectionHandler = null; processor(pending); } } function _createSettleIfFn(newState, allowState) { return (theValue) => { if (_state === allowState) { if (newState === 2 && tsUtils.isPromiseLike(theValue)) { _state = 1; theValue.then(_createSettleIfFn(2, 1), _createSettleIfFn(3, 1)); return; } _state = newState; _hasResolved = true; _settledValue = theValue; _processQueue(); if (!_handled && newState === 3 && !_unHandledRejectionHandler) { _unHandledRejectionHandler = tsUtils.scheduleTimeout(_notifyUnhandledRejection, _unhandledRejectionTimeout); } } }; } function _notifyUnhandledRejection() { if (!_handled) { _handled = true; if (tsUtils.isNode()) { process.emit(NODE_UNHANDLED_REJECTION, _settledValue, _thePromise); } else { let gbl = tsUtils.getWindow() || tsUtils.getGlobal(); !_hasPromiseRejectionEvent && (_hasPromiseRejectionEvent = tsUtils.createCachedValue(tsUtils.safe((tsUtils.getInst), [STR_PROMISE + "RejectionEvent"]).v)); emitEvent(gbl, UNHANDLED_REJECTION, (theEvt) => { tsUtils.objDefine(theEvt, "promise", { g: () => _thePromise }); theEvt.reason = _settledValue; return theEvt; }, !!_hasPromiseRejectionEvent.v); } } } _thePromise = { then: _then, "catch": _catch, finally: _finally }; tsUtils.objDefineProp(_thePromise, "state", { get: _strState }); if (_promiseDebugEnabled) { _addDebugState$1(_thePromise, _strState, () => { return tsUtils.objToString(_settledValue); }, () => _handled); } if (tsUtils.hasSymbol()) { _thePromise[tsUtils.getKnownSymbol(11)] = "IPromise"; } function _toString() { return "IPromise" + (_promiseDebugEnabled ? "[" + _id + (!tsUtils.isUndefined(_parentId) ? (":" + _parentId) : "") + "]" : "") + " " + _strState() + (_hasResolved ? (" - " + dumpFnObj(_settledValue)) : "") + (""); } _thePromise.toString = _toString; (function _initialize() { if (!tsUtils.isFunction(executor)) { tsUtils.throwTypeError(STR_PROMISE + ": executor is not a function - " + dumpFnObj(executor)); } const _rejectFn = _createSettleIfFn(3, 0); try { executor.call(_thePromise, _createSettleIfFn(2, 0), _rejectFn); } catch (e) { _rejectFn(e); } })(); return _thePromise; } function _createAllPromise(newPromise) { return function (input) { let additionalArgs = tsUtils.arrSlice(arguments, 1); return newPromise((resolve, reject) => { try { let values = []; let pending = 1; tsUtils.iterForOf(input, (item, idx) => { if (item) { pending++; doAwait(item, (value) => { values[idx] = value; if (--pending === 0) { resolve(values); } }, reject); } }); pending--; if (pending === 0) { resolve(values); } } catch (e) { reject(e); } }, additionalArgs); }; } function _createResolvedPromise(newPromise) { return function (value) { let additionalArgs = tsUtils.arrSlice(arguments, 1); if (tsUtils.isPromiseLike(value)) { return value; } return newPromise((resolve) => { resolve(value); }, additionalArgs); }; } function _createRejectedPromise(newPromise) { return function (reason) { let additionalArgs = tsUtils.arrSlice(arguments, 1); return newPromise((_resolve, reject) => { reject(reason); }, additionalArgs); }; } function _createAllSettledPromise(newPromise, ..._args) { return tsUtils.createCachedValue(function (input, ..._args) { let additionalArgs = tsUtils.arrSlice(arguments, 1); return newPromise((resolve, reject) => { let values = []; let pending = 1; function processItem(item, idx) { pending++; doAwaitResponse(item, (value) => { if (value.rejected) { values[idx] = { status: REJECTED, reason: value.reason }; } else { values[idx] = { status: "fulfilled", value: value.value }; } if (--pending === 0) { resolve(values); } }); } try { if (tsUtils.isArray(input)) { tsUtils.arrForEach(input, processItem); } else if (tsUtils.isIterable(input)) { tsUtils.iterForOf(input, processItem); } else { tsUtils.throwTypeError("Input is not an iterable"); } pending--; if (pending === 0) { resolve(values); } } catch (e) { reject(e); } }, additionalArgs); }); } function _createRacePromise(newPromise, ..._args) { return tsUtils.createCachedValue(function (input, ..._args) { let additionalArgs = tsUtils.arrSlice(arguments, 1); return newPromise((resolve, reject) => { let isDone = false; function processItem(item) { doAwaitResponse(item, (value) => { if (!isDone) { isDone = true; if (value.rejected) { reject(value.reason); } else { resolve(value.value); } } }); } try { if (tsUtils.isArray(input)) { tsUtils.arrForEach(input, processItem); } else if (tsUtils.isIterable(input)) { tsUtils.iterForOf(input, processItem); } else { tsUtils.throwTypeError("Input is not an iterable"); } } catch (e) { reject(e); } }, additionalArgs); }); } function _createAnyPromise(newPromise, ..._args) { return tsUtils.createCachedValue(function (input, ..._args) { let additionalArgs = tsUtils.arrSlice(arguments, 1); return newPromise((resolve, reject) => { let theErros = []; let pending = 1; let isDone = false; function processItem(item, idx) { pending++; doAwaitResponse(item, (value) => { if (!value.rejected) { isDone = true; resolve(value.value); return; } else { theErros[idx] = value.reason; } if (--pending === 0 && !isDone) { reject(_createAggregationError(theErros)); } }); } try { if (tsUtils.isArray(input)) { tsUtils.arrForEach(input, processItem); } else if (tsUtils.isIterable(input)) { tsUtils.iterForOf(input, processItem); } else { tsUtils.throwTypeError("Input is not an iterable"); } pending--; if (pending === 0 && !isDone) { reject(_createAggregationError(theErros)); } } catch (e) { reject(e); } }, additionalArgs); }); } function syncItemProcessor(pending) { tsUtils.arrForEach(pending, (fn) => { try { fn(); } catch (e) { } }); } function timeoutItemProcessor(timeout) { let callbackTimeout = tsUtils.isNumber(timeout) ? timeout : 0; return (pending) => { tsUtils.scheduleTimeout(() => { syncItemProcessor(pending); }, callbackTimeout); }; } function idleItemProcessor(timeout) { let options; if (timeout >= 0) { options = { timeout: +timeout }; } return (pending) => { tsUtils.scheduleIdleCallback((deadline) => { syncItemProcessor(pending); }, options); }; } let _allAsyncSettledCreator; let _raceAsyncCreator; let _anyAsyncCreator; function createAsyncPromise(executor, timeout) { return _createPromise(createAsyncPromise, timeoutItemProcessor(timeout), executor, timeout); } const createAsyncAllPromise = (_createAllPromise(createAsyncPromise)); const createAsyncResolvedPromise = (_createResolvedPromise(createAsyncPromise)); const createAsyncRejectedPromise = (_createRejectedPromise(createAsyncPromise)); function createAsyncAllSettledPromise(input, timeout) { !_allAsyncSettledCreator && (_allAsyncSettledCreator = _createAllSettledPromise(createAsyncPromise)); return _allAsyncSettledCreator.v(input, timeout); } function createAsyncRacePromise(values, timeout) { !_raceAsyncCreator && (_raceAsyncCreator = _createRacePromise(createAsyncPromise)); return _raceAsyncCreator.v(values, timeout); } function createAsyncAnyPromise(values, timeout) { !_anyAsyncCreator && (_anyAsyncCreator = _createAnyPromise(createAsyncPromise)); return _anyAsyncCreator.v(values, timeout); } let _promiseCls; let _allCreator; let _allNativeSettledCreator; let _raceNativeCreator; let _anyNativeCreator; function _createNativePromiseHelper(name, func) { !_promiseCls && (_promiseCls = tsUtils.createCachedValue((tsUtils.safe(tsUtils.getInst, [STR_PROMISE]).v) || null)); if (_promiseCls.v && _promiseCls.v[name]) { return tsUtils.createCachedValue(function (input, timeout) { return createNativePromise((resolve, reject) => { _promiseCls.v[name](input).then(resolve, reject); }); }); } return func(); } function createNativePromise(executor, timeout) { !_promiseCls && (_promiseCls = tsUtils.createCachedValue((tsUtils.safe(tsUtils.getInst, [STR_PROMISE]).v) || null)); const PrmCls = _promiseCls.v; if (!PrmCls) { return createAsyncPromise(executor); } if (!tsUtils.isFunction(executor)) { tsUtils.throwTypeError(STR_PROMISE + ": executor is not a function - " + tsUtils.dumpObj(executor)); } let _state = 0; function _strState() { return STRING_STATES[_state]; } let thePromise = new PrmCls((resolve, reject) => { function _resolve(value) { _state = 2; resolve(value); } function _reject(reason) { _state = 3; reject(reason); } executor(_resolve, _reject); }); tsUtils.objDefineProp(thePromise, "state", { get: _strState }); return thePromise; } function createNativeAllPromise(input, timeout) { !_allCreator && (_allCreator = _createNativePromiseHelper("all", () => tsUtils.createCachedValue(_createAllPromise(createNativePromise)))); return _allCreator.v(input, timeout); } const createNativeResolvedPromise = (_createResolvedPromise(createNativePromise)); const createNativeRejectedPromise = (_createRejectedPromise(createNativePromise)); function createNativeAllSettledPromise(input, timeout) { !_allNativeSettledCreator && (_allNativeSettledCreator = _createNativePromiseHelper("allSettled", () => _createAllSettledPromise(createNativePromise))); return _allNativeSettledCreator.v(input, timeout); } function createNativeRacePromise(values, timeout) { !_raceNativeCreator && (_raceNativeCreator = _createNativePromiseHelper("race", () => _createRacePromise(createNativePromise))); return _raceNativeCreator.v(values, timeout); } function createNativeAnyPromise(values, timeout) { !_anyNativeCreator && (_anyNativeCreator = _createNativePromiseHelper("any", () => _createAnyPromise(createNativePromise))); return _anyNativeCreator.v(values, timeout); } let _allSyncSettledCreator; let _raceSyncCreator; let _anySyncCreator; function createSyncPromise(executor) { return _createPromise(createSyncPromise, syncItemProcessor, executor); } const createSyncAllPromise = (_createAllPromise(createSyncPromise)); const createSyncResolvedPromise = (_createResolvedPromise(createSyncPromise)); const createSyncRejectedPromise = (_createRejectedPromise(createSyncPromise)); function createSyncAllSettledPromise(input, timeout) { !_allSyncSettledCreator && (_allSyncSettledCreator = _createAllSettledPromise(createSyncPromise)); return _allSyncSettledCreator.v(input, timeout); } function createSyncRacePromise(values, timeout) { !_raceSyncCreator && (_raceSyncCreator = _createRacePromise(createSyncPromise)); return _raceSyncCreator.v(values, timeout); } function createSyncAnyPromise(values, timeout) { !_anySyncCreator && (_anySyncCreator = _createAnyPromise(createSyncPromise)); return _anySyncCreator.v(values, timeout); } let _defaultIdleTimeout; let _allIdleSettledCreator; let _raceIdleCreator; let _anyIdleCreator; function setDefaultIdlePromiseTimeout(idleDeadline) { _defaultIdleTimeout = idleDeadline; } const setDefaultIdleTimeout = (_pureAssign(setDefaultIdlePromiseTimeout)); function createIdlePromise(executor, timeout) { let theTimeout = tsUtils.isUndefined(timeout) ? _defaultIdleTimeout : timeout; return _createPromise(createIdlePromise, idleItemProcessor(theTimeout), executor, theTimeout); } const createIdleAllPromise = (_createAllPromise(createIdlePromise)); const createIdleResolvedPromise = (_createResolvedPromise(createIdlePromise)); const createIdleRejectedPromise = (_createRejectedPromise(createIdlePromise)); function createIdleAllSettledPromise(input, timeout) { !_allIdleSettledCreator && (_allIdleSettledCreator = _createAllSettledPromise(createIdlePromise)); return _allIdleSettledCreator.v(input, timeout); } function createIdleRacePromise(values, timeout) { !_raceIdleCreator && (_raceIdleCreator = _createRacePromise(createIdlePromise)); return _raceIdleCreator.v(values, timeout); } function createIdleAnyPromise(values, timeout) { !_anyIdleCreator && (_anyIdleCreator = _createAnyPromise(createIdlePromise)); return _anyIdleCreator.v(values, timeout); } let _promiseCreator; let _allSettledCreator; let _raceCreator; let _anyCreator; function setCreatePromiseImpl(creator) { _promiseCreator = creator ? tsUtils.createCachedValue(creator) : null; } function createPromise(executor, timeout) { !_promiseCreator && (_promiseCreator = tsUtils.createCachedValue(createNativePromise)); return _promiseCreator.v.call(this, executor, timeout); } const createAllPromise = (_createAllPromise(createPromise)); const createResolvedPromise = (_createResolvedPromise(createPromise)); const createRejectedPromise = (_createRejectedPromise(createPromise)); function createAllSettledPromise(input, timeout) { !_allSettledCreator && (_allSettledCreator = _createAllSettledPromise(createPromise)); return _allSettledCreator.v(input, timeout); } function createRacePromise(values, timeout) { !_raceCreator && (_raceCreator = _createRacePromise(createPromise)); return _raceCreator.v(values, timeout); } function createAnyPromise(values, timeout) { !_anyCreator && (_anyCreator = _createAnyPromise(createPromise)); return _anyCreator.v(values, timeout); } function createTimeoutPromise(timeout, resolveReject, message) { return createPromise((resolve, reject) => { tsUtils.scheduleTimeout(() => { (resolveReject ? resolve : reject)(!tsUtils.isUndefined(message) ? message : "Timeout of " + timeout + "ms exceeded"); }, timeout); }); } function _doneChk(isDone, state, value, thisArg) { let result = isDone; state.res = value; if (!result) { if (state.isDone && tsUtils.isFunction(state.isDone)) { return doAwait(state.isDone.call(thisArg, state), (done) => { state.iter++; return !!done; }); } else { result = !!state.isDone; } } state.iter++; return result; } function doWhileAsync(callbackFn, isDoneFn, thisArg) { let promise; let resolve; let reject = (reason) => { isDone = true; throw reason; }; let isDone = false; let state = { st: tsUtils.utcNow(), iter: 0, isDone: isDoneFn || false }; if (callbackFn) { const _createPromise = () => { return createPromise((res, rej) => { resolve = res; reject = rej; }); }; const _handleAsyncDone = (done) => { isDone = !!done; if (!isDone) { _processNext(); } else { resolve(state.res); } }; const _processNext = () => { while (!isDone) { try { let cbResult = callbackFn.call(thisArg, state); if (tsUtils.isPromiseLike(cbResult)) { promise = promise || _createPromise(); doAwait(cbResult, (res) => { try { doAwait(_doneChk(isDone, state, res, thisArg), _handleAsyncDone, reject); } catch (e) { reject(e); } }, reject); return promise; } else { let dnRes = _doneChk(isDone, state, cbResult, thisArg); if (tsUtils.isPromiseLike(dnRes)) { promise = promise || _createPromise(); doAwait(dnRes, _handleAsyncDone, reject); return promise; } else { isDone = !!dnRes; } } } catch (e) { reject(e); return promise; } } if (isDone && resolve) { resolve(state.res); } return promise || state.res; }; return _processNext(); } } function arrForEachAsync(theArray, callbackFn, thisArg) { if (theArray) { const len = tsUtils.getLength(theArray); if (len) { const isDone = (state) => { if (state.iter >= len || state.res === -1) { return true; } }; return doWhileAsync((state) => { const idx = state.iter; if (idx in theArray) { return callbackFn.call(thisArg || theArray, theArray[idx], idx, theArray); } }, isDone); } } } let _iterSymbol; let _iterAsyncSymbol; function iterForOfAsync(iter, callbackFn, thisArg) { let err; let iterResult; let theIter = iter; function onFailed(failed) { err = { e: failed }; if (theIter.throw) { iterResult = null; theIter.throw(err); } throw failed; } function onFinally() { try { if (iterResult && !iterResult[DONE]) { theIter[RETURN] && theIter[RETURN](iterResult); } } finally { if (err) { throw err.e; } } } if (iter) { if (!tsUtils.isIterator(iter)) { !_iterAsyncSymbol && (_iterAsyncSymbol = tsUtils.createCachedValue(tsUtils.getKnownSymbol(0))); theIter = iter[_iterAsyncSymbol.v] ? iter[_iterAsyncSymbol.v]() : null; if (!theIter) { !_iterSymbol && (_iterSymbol = tsUtils.createCachedValue(tsUtils.getKnownSymbol(3))); theIter = iter[_iterSymbol.v] ? iter[_iterSymbol.v]() : null; } } if (theIter && tsUtils.isIterator(theIter)) { let result; try { result = doWhileAsync((state) => { return doAwait(theIter.next(), (res) => { iterResult = res; if (!res[DONE]) { return tsUtils.fnCall(callbackFn, thisArg || theIter, iterResult[VALUE], state.iter, theIter); } }, (reason) => { state.isDone = true; onFailed(reason); }); }, (state) => { if (!iterResult || iterResult[DONE] || state.res === -1) { onFinally(); return true; } }, thisArg || theIter); if (tsUtils.isPromiseLike(result)) { result = doFinally(result.catch(onFailed), onFinally); } return result; } catch (failed) { onFailed(failed); } finally { if (result && !tsUtils.isPromiseLike(result)) { onFinally(); } } } } } const REJECT = "reject"; const REJECTED_ERROR = "Rejected"; let _schedulerId = 0; let _debugName; let _debugIntState; let _customErrors = {}; function _rejectDone() { } function _createError(type, evt, message) { !_customErrors[type] && (_customErrors[type] = tsUtils.createCustomError(type)); let now = tsUtils.utcNow(); return new (_customErrors[type])(`Task [${evt.id}] ${message || ""}- ${(evt.st ? "Running" : "Waiting")}: ${_calcTime(now, evt.st || evt.cr)}`); } function _calcTime(now, start) { return ((now - start) || "0") + " ms"; } function _abortStaleTasks(taskQueue, staleTimeoutPeriod) { let now = tsUtils.utcNow(); let expired = now - staleTimeoutPeriod; tsUtils.arrForEach(taskQueue, (evt) => { if (evt && !evt.rj && (evt.st && evt.st < expired) || (!evt.st && evt.cr && evt.cr < expired)) { evt && evt[REJECT](evt.rj || _createError("Aborted", evt, "Stale ")); } }); } function _removeTask(queue, taskDetail) { let idx = tsUtils.arrIndexOf(queue, taskDetail); if (idx !== -1) { queue.splice(idx, 1); } } function _addDebugState(theScheduler, nameFn, stateFn) { _debugName = _debugName || { toString: () => "[[SchedulerName]]" }; _debugIntState = _debugIntState || { toString: () => "[[SchedulerState]]" }; tsUtils.objDefineProp(theScheduler, _debugName, { get: nameFn }); tsUtils.objDefineProp(theScheduler, _debugIntState, { get: stateFn }); } function createTaskScheduler(newPromise, name) { let _theTask; let _running = []; let _waiting = []; let _staleTimeoutPeriod = 600000; let _staleTimeoutCheckPeriod = _staleTimeoutPeriod / 10; let _taskCount = 0; let _schedulerName = (name ? (name + ".") : "") + _schedulerId++; let _blockedTimer; newPromise = newPromise || createPromise; const _startBlockedTimer = () => { let hasTasks = (tsUtils.getLength(_running) + tsUtils.getLength(_waiting)) > 0; if (_staleTimeoutPeriod > 0) { if (!_blockedTimer) { _blockedTimer = tsUtils.scheduleTimeout(() => { _abortStaleTasks(_running, _staleTimeoutPeriod); _abortStaleTasks(_waiting, _staleTimeoutPeriod); _blockedTimer && (_blockedTimer.enabled = ((tsUtils.getLength(_running) + tsUtils.getLength(_waiting)) > 0)); }, _staleTimeoutCheckPeriod); _blockedTimer.unref(); } _blockedTimer && (_blockedTimer.enabled = hasTasks); } }; const _queueTask = (startAction, taskName, timeout) => { let taskId = _schedulerName + "." + _taskCount++; if (taskName) { taskId += "-(" + taskName + ")"; } let newTask = { id: taskId, cr: tsUtils.utcNow(), to: timeout, [REJECT]: (reason) => { newTask.rj = reason || _createError(REJECTED_ERROR, newTask); newTask[REJECT] = _rejectDone; } }; if (!_theTask) { newTask.p = newPromise(_runTask(newTask, startAction)); } else { newTask.p = _waitForPreviousTask(newTask, _theTask, startAction); } _theTask = newTask; return newTask.p; }; const _runTask = (taskDetail, startAction) => { taskDetail.st = tsUtils.utcNow(); _running.push(taskDetail); _startBlockedTimer(); return (onTaskResolve, onTaskReject) => { const _promiseReject = (reason) => { taskDetail.rj = taskDetail.rj || reason || _createError(REJECTED_ERROR, taskDetail); taskDetail[REJECT] = _rejectDone; _doCleanup(taskDetail); onTaskResolve = null; onTaskReject && onTaskReject(reason); onTaskReject = null; }; let taskId = taskDetail.id; if (taskDetail.rj) { _promiseReject(taskDetail.rj); } else { taskDetail[REJECT] = _promiseReject; try { let startResult = startAction(taskId); if (taskDetail.to && tsUtils.isPromiseLike(startResult)) { taskDetail.t = tsUtils.scheduleTimeout(() => { _promiseReject(_createError("Timeout", taskDetail)); }, taskDetail.to); } doAwait(startResult, (theResult) => { _doCleanup(taskDetail); try { onTaskResolve && onTaskResolve(theResult); } catch (e) { onTaskReject && onTaskReject(e); } onTaskReject = null; onTaskResolve = null; }, _promiseReject); } catch (e) { _promiseReject(e); } } }; }; const _waitForPreviousTask = (taskDetail, prevTask, startAction) => { _waiting.push(taskDetail); _startBlockedTimer(); return newPromise((onWaitResolve, onWaitReject) => { doAwaitResponse(prevTask.p, () => { _removeTask(_waiting, taskDetail); _runTask(taskDetail, startAction)(onWaitResolve, onWaitReject); }); }); }; const _doCleanup = (taskDetail) => { _removeTask(_running, taskDetail); taskDetail.t && taskDetail.t.cancel(); taskDetail.t = null; if (_theTask && _theTask === taskDetail) { _theTask = null; if (tsUtils.getLength(_running) + tsUtils.getLength(_waiting) === 0) { _blockedTimer && _blockedTimer.cancel(); _blockedTimer = null; } } }; let theScheduler = { idle: true, queue: _queueTask, setStaleTimeout: (staleTimeout, staleCheckPeriod) => { _blockedTimer && _blockedTimer.cancel(); _blockedTimer = null; _staleTimeoutPeriod = staleTimeout; _staleTimeoutCheckPeriod = staleCheckPeriod || staleTimeout / 10; _startBlockedTimer(); } }; tsUtils.objDefine(theScheduler, "idle", { g: () => { return tsUtils.getLength(_running) + tsUtils.getLength(_waiting) === 0; } }); _addDebugState(theScheduler, () => _schedulerName, () => { return { l: _theTask, r: _running, w: _waiting }; }); return theScheduler; } const toStringTagSymbol = tsUtils.getKnownSymbol(11); let PolyPromise = ((function () { function PolyPromiseImpl(executor) { this._$ = createAsyncPromise(executor); if (toStringTagSymbol) { this[toStringTagSymbol] = "Promise"; } tsUtils.objDefineProp(this, "state", { get: function () { return this._$.state; } }); } PolyPromiseImpl.all = createAsyncAllPromise; PolyPromiseImpl.race = createAsyncRacePromise; PolyPromiseImpl.any = createAsyncAnyPromise; PolyPromiseImpl.reject = createAsyncRejectedPromise; PolyPromiseImpl.resolve = createAsyncResolvedPromise; PolyPromiseImpl.allSettled = createAsyncAllSettledPromise; let theProto = PolyPromiseImpl.prototype; theProto.then = function (onResolved, onRejected) { return this._$.then(onResolved, onRejected); }; theProto.catch = function (onRejected) { return this._$.catch(onRejected); }; theProto.finally = function (onfinally) { return this._$.finally(onfinally); }; return PolyPromiseImpl; }())); exports.PolyPromise = PolyPromise; exports.arrForEachAsync = arrForEachAsync; exports.createAllPromise = createAllPromise; exports.createAllSettledPromise = createAllSettledPromise; exports.createAnyPromise = createAnyPromise; exports.createAsyncAllPromise = createAsyncAllPromise; exports.createAsyncAllSettledPromise = createAsyncAllSettledPromise; exports.createAsyncAnyPromise = createAsyncAnyPromise; exports.createAsyncPromise = createAsyncPromise; exports.createAsyncRacePromise = createAsyncRacePromise; exports.createAsyncRejectedPromise = createAsyncRejectedPromise; exports.createAsyncResolvedPromise = createAsyncResolvedPromise; exports.createIdleAllPromise = createIdleAllPromise; exports.createIdleAllSettledPromise = createIdleAllSettledPromise; exports.createIdleAnyPromise = createIdleAnyPromise; exports.createIdlePromise = createIdlePromise; exports.createIdleRacePromise = createIdleRacePromise; exports.createIdleRejectedPromise = createIdleRejectedPromise; exports.createIdleResolvedPromise = createIdleResolvedPromise; exports.createNativeAllPromise = createNativeAllPromise; exports.createNativeAllSettledPromise = createNativeAllSettledPromise; exports.createNativeAnyPromise = createNativeAnyPromise; exports.createNativePromise = createNativePromise; exports.createNativeRacePromise = createNativeRacePromise; exports.createNativeRejectedPromise = createNativeRejectedPromise; exports.createNativeResolvedPromise = createNativeResolvedPromise; exports.createPromise = createPromise; exports.createRacePromise = createRacePromise; exports.createRejectedPromise = createRejectedPromise; exports.createResolvedPromise = createResolvedPromise; exports.createSyncAllPromise = createSyncAllPromise; exports.createSyncAllSettledPromise = createSyncAllSettledPromise; exports.createSyncAnyPromise = createSyncAnyPromise; exports.createSyncPromise = createSyncPromise; exports.createSyncRacePromise = createSyncRacePromise; exports.createSyncRejectedPromise = createSyncRejectedPromise; exports.createSyncResolvedPromise = createSyncResolvedPromise; exports.createTaskScheduler = createTaskScheduler; exports.createTimeoutPromise = createTimeoutPromise; exports.doAwait = doAwait; exports.doAwaitResponse = doAwaitResponse; exports.doFinally = doFinally; exports.doWhileAsync = doWhileAsync; exports.iterForOfAsync = iterForOfAsync; exports.setCreatePromiseImpl = setCreatePromiseImpl; exports.setDefaultIdlePromiseTimeout = setDefaultIdlePromiseTimeout; exports.setDefaultIdleTimeout = setDefaultIdleTimeout; exports.setPromiseDebugState = setPromiseDebugState; })); //# sourceMappingURL=ts-async.js.map