From 6e0bc30c6d36b4c941973b1e0a3395e5a2cfd627 Mon Sep 17 00:00:00 2001 From: nev21 <82737406+nev21@users.noreply.github.com> Date: Sun, 18 Feb 2024 00:18:41 -0800 Subject: [PATCH] [Bug] createAllPromise signature is different from native Promise.all #116 (#127) --- .npmignore | 2 +- README.md | 30 +- common/config/rush/npm-shrinkwrap.json | 81 ++-- common/scripts/install-run.js | 15 +- lib/package.json | 2 +- lib/rollup.config.js | 34 +- lib/src/helpers/doWhileAsync.ts | 6 +- lib/src/helpers/iterForOfAsync.ts | 67 +-- lib/src/index.ts | 14 +- lib/src/interfaces/IPromiseResult.ts | 44 ++ lib/src/interfaces/await-response.ts | 46 +- lib/src/internal/constants.ts | 3 +- lib/src/internal/state.ts | 6 +- lib/src/polyfills.ts | 5 +- lib/src/polyfills/promise.ts | 21 +- lib/src/promise/asyncPromise.ts | 94 +++- lib/src/promise/await.ts | 7 +- lib/src/promise/base.ts | 78 ++- lib/src/promise/debug.ts | 2 +- lib/src/promise/event.ts | 29 +- lib/src/promise/idlePromise.ts | 95 +++- lib/src/promise/itemProcessor.ts | 2 +- lib/src/promise/nativePromise.ts | 102 +++- lib/src/promise/promise.ts | 106 +++- lib/src/promise/syncPromise.ts | 94 +++- lib/src/promise/timeoutPromise.ts | 4 +- lib/src/scheduler/taskScheduler.ts | 4 +- lib/test/src/promise/await.test.ts | 6 + lib/test/src/promise/use.await.test.ts | 592 ++++++++++++++++------- lib/test/src/promise/use.doAwait.test.ts | 5 +- lib/test/src/scheduler/scheduler.test.ts | 26 +- package.json | 10 +- rush.json | 2 +- tools/build-tools/pre-proc/package.json | 2 +- 34 files changed, 1265 insertions(+), 371 deletions(-) create mode 100644 lib/src/interfaces/IPromiseResult.ts diff --git a/.npmignore b/.npmignore index ba911ed..ab9ebe2 100644 --- a/.npmignore +++ b/.npmignore @@ -10,6 +10,6 @@ !/LICENSE !lib/dist-esm/** !lib/dist/** -!lib/browser/** +!lib/bundle/** !lib/src/** !lib/types/** \ No newline at end of file diff --git a/README.md b/README.md index eecb990..b77a49b 100644 --- a/README.md +++ b/README.md @@ -30,24 +30,30 @@ See [Browser Support](#browser-support) for details on the supported browser env | Type / Function | Details |-----------------------|------------------------------ -| **Scheduler** +| **Promise based Scheduler** | [`createTaskScheduler`](https://nevware21.github.io/ts-async/typedoc/functions/createTaskScheduler.html) | Create a Task Scheduler using the optional promise implementation and scheduler name. The newPromise can be any value promise creation function, where the execution of the queued tasks will be processed based on how the promise implementation processes it's chained promises (asynchrounsly; synchronously; idle processing, etc)
There is no limit on the number of schedulers that you can create, when using more than one scheduler it is recommended that you provide a `name` to each scheduler to help identify / group promises during debugging. | **Interfaces** | [`IPromise`](https://nevware21.github.io/ts-async/typedoc/interfaces/IPromise.html) | This package uses and exports the `IPromise` interface which extends both the `PromiseLike` and `Promise` to provide type compatibility when passing the Promises created with this package to any function that expects a `Promise` (including returning from an `async function`). As part of it's definition it exposes an [optional] string `status` to represent the current state of the `Promise`. These values include `pending`, `resolved` `rejected` and `resolving` which is a special case when a Promise is being `resolved` via another Promise returned via the `thenable` onResolved / onRejected functions. -| [`AwaitResponse`](https://nevware21.github.io/ts-async/typedoc/interfaces/AwaitResponse.html) | This interface is used to represent the result whether resolved or rejected when using the [`doAwaitResponse`](https://nevware21.github.io/ts-async/typedoc/functions/doAwaitResponse.html), this function is useful when you want to avoid creating both a `resolved` and `rejected` functions, as this function only requires a single callback function to be used which will receive an object that conforms to this interface. +| [`AwaitResponse`](https://nevware21.github.io/ts-async/typedoc/interfaces/AwaitResponse.html) | This interface is used to represent the result whether resolved or rejected when using the [`doAwaitResponse`](https://nevware21.github.io/ts-async/typedoc/functions/doAwaitResponse.html), this function is useful when you want to avoid creating both a `resolved` and `rejected` functions, as this function only requires a single callback function to be used which will receive an object that conforms to this interface. +| [`IWhileState`](https://nevware21.github.io/ts-async/typedoc/interfaces/IWhileState.html) | The current state of the while loop while processing the callback function, this is passed to eht callback function. +| [`IPromiseResult`](https://nevware21.github.io/ts-async/typedoc/interfaces/IPromiseResult.html) |The result of a promise. It can either be fulfilled with a value, or rejected with a reason. | **Alias** -| [`createPromise`](https://nevware21.github.io/ts-async/typedoc/functions/createPromise.html)
[`createAllPromise`](https://nevware21.github.io/ts-async/typedoc/functions/createAllPromise.html)
[`createRejectedPromise`](https://nevware21.github.io/ts-async/typedoc/functions/createRejectedPromise.html)
[`createResolvedPromise`](https://nevware21.github.io/ts-async/typedoc/functions/createResolvedPromise.html)

[`setCreatePromiseImpl`](https://nevware21.github.io/ts-async/typedoc/functions/setCreatePromiseImpl.html) | These function use the current promise creator implementation that can be set via [`setCreatePromiseImpl`](https://nevware21.github.io/ts-async/typedoc/functions/setCreatePromiseImpl.html)(creator: <T>(executor: PromiseExecutor<T>, timeout?: number) => IPromise<T>): void
Unless otherwise set this defaults to the `createNativePromise` implementation, to provide a simplified wrapper around any native runtime Promise support.
Available implementation:
  • [`createNativePromise`](https://nevware21.github.io/ts-async/typedoc/functions/createNativePromise.html)
  • [`createAsyncPromise`](https://nevware21.github.io/ts-async/typedoc/functions/createAsyncPromise.html)
  • [`createSyncPromise`](https://nevware21.github.io/ts-async/typedoc/functions/createSyncPromise.html)
  • [`createIdlePromise`](https://nevware21.github.io/ts-async/typedoc/functions/createIdlePromise.html)
By using these aliases, it's possible to switch between any of these implementations as needed without duplicating your code. This will not change any existing promises, it only affects new promises. -| [`createNativePromise`](https://nevware21.github.io/ts-async/typedoc/functions/createNativePromise.html)
[`createNativeAllPromise`](https://nevware21.github.io/ts-async/typedoc/functions/createNativeAllPromise.html)
[`createNativeRejectedPromise`](https://nevware21.github.io/ts-async/typedoc/functions/createNativeRejectedPromise.html)
[`createNativeResolvedPromise`](https://nevware21.github.io/ts-async/typedoc/functions/createNativeResolvedPromise.html)
| These are effectively wrappers around the runtime `Promise` class, so this is effectivly the same as `new Promise(...)` but as a non-global class name it can be heavily minified to something like `a(...)`. These wrappers also add an accessible `status` property for identifying the current status of this promise. However, the `status` property is NOT available on any returned chained Promise (from calling `then`, `catch` or `finally`) -| **Asynchronous** -| [`createAsyncPromise`](https://nevware21.github.io/ts-async/typedoc/functions/createAsyncPromise.html)
[`createAsyncAllPromise`](https://nevware21.github.io/ts-async/typedoc/functions/createAsyncAllPromise.html)
[`createAsyncRejectedPromise`](https://nevware21.github.io/ts-async/typedoc/functions/createAsyncRejectedPromise.html)
[`createAsyncResolvedPromise`](https://nevware21.github.io/ts-async/typedoc/functions/createAsyncResolvedPromise.html)
| Provides an implementation of the `Promise` contract that uses timeouts to process any chained promises (returned by `then(...)`, `catch(...)`, `finally(...)`), when creating the initial promise you can also provide (override) the default duration of the timeout (defaults to 0ms) to further delay the execution of the chained Promises.
, but can also be provided) to process any chained promises (of any type) -| **Synchronous** -| [`createSyncPromise`](https://nevware21.github.io/ts-async/typedoc/functions/createSyncPromise.html)
[`createSyncAllPromise`](https://nevware21.github.io/ts-async/typedoc/functions/createSyncAllPromise.html)
[`createSyncRejectedPromise`](https://nevware21.github.io/ts-async/typedoc/functions/createSyncRejectedPromise.html)
[`createSyncResolvedPromise`](https://nevware21.github.io/ts-async/typedoc/functions/createSyncResolvedPromise.html)
| Also implements the `Promise` contract but will immediately execute any chained promises at the point of the original promise getting resolved or rejected, or if already resolved, rejected then at the point of registering the `then`, `catch` or `finally` -| **Idle** -| [`createIdlePromise`](https://nevware21.github.io/ts-async/typedoc/functions/createIdlePromise.html)
[`createIdleAllPromise`](https://nevware21.github.io/ts-async/typedoc/functions/createIdleAllPromise.html)
[`createIdleRejectedPromise`](https://nevware21.github.io/ts-async/typedoc/functions/createIdleRejectedPromise.html)
[`createIdleResolvedPromise`](https://nevware21.github.io/ts-async/typedoc/functions/createIdleResolvedPromise.html)
| Implements the `Promise` contract and will process any chained promises using the available `requestIdleCallback` (with no timeout by default - but can also be changes by `setDetaultIdlePromiseTimeout`). And when `requestIdleCallback` is not supported this will default to using a timeout via the [`scheduleIdleCallback` from `@nevware21/ts-utils`](https://nevware21.github.io/ts-utils/typedoc/functions/scheduleIdleCallback.html) +| [`createPromise`](https://nevware21.github.io/ts-async/typedoc/functions/createPromise.html)
[`createAllPromise`](https://nevware21.github.io/ts-async/typedoc/functions/createAllPromise.html)
[`createRejectedPromise`](https://nevware21.github.io/ts-async/typedoc/functions/createRejectedPromise.html)
[`createResolvedPromise`](https://nevware21.github.io/ts-async/typedoc/functions/createResolvedPromise.html)
[`createAllSettledPromise`](https://nevware21.github.io/ts-async/typedoc/functions/createAllSettledPromise.html)

[`setCreatePromiseImpl`](https://nevware21.github.io/ts-async/typedoc/functions/setCreatePromiseImpl.html) | These function use the current promise creator implementation that can be set via [`setCreatePromiseImpl`](https://nevware21.github.io/ts-async/typedoc/functions/setCreatePromiseImpl.html)(creator: <T>(executor: PromiseExecutor<T>, timeout?: number) => IPromise<T>): void
Unless otherwise set this defaults to the `createNativePromise` implementation, to provide a simplified wrapper around any native runtime Promise support.
Available implementation:
  • [`createNativePromise`](https://nevware21.github.io/ts-async/typedoc/functions/createNativePromise.html)
  • [`createAsyncPromise`](https://nevware21.github.io/ts-async/typedoc/functions/createAsyncPromise.html)
  • [`createSyncPromise`](https://nevware21.github.io/ts-async/typedoc/functions/createSyncPromise.html)
  • [`createIdlePromise`](https://nevware21.github.io/ts-async/typedoc/functions/createIdlePromise.html)
By using these aliases, it's possible to switch between any of these implementations as needed without duplicating your code. This will not change any existing promises, it only affects new promises. +| [`createNativePromise`](https://nevware21.github.io/ts-async/typedoc/functions/createNativePromise.html)
[`createNativeAllPromise`](https://nevware21.github.io/ts-async/typedoc/functions/createNativeAllPromise.html)
[`createNativeRejectedPromise`](https://nevware21.github.io/ts-async/typedoc/functions/createNativeRejectedPromise.html)
[`createNativeResolvedPromise`](https://nevware21.github.io/ts-async/typedoc/functions/createNativeResolvedPromise.html)
[`createNativeAllSettledPromise`](https://nevware21.github.io/ts-async/typedoc/functions/createNativeAllSettledPromise.html) | These are effectively wrappers around the runtime `Promise` class, so this is effectivly the same as `new Promise(...)` but as a non-global class name it can be heavily minified to something like `a(...)`. These wrappers also add an accessible `status` property for identifying the current status of this promise. However, the `status` property is NOT available on any returned chained Promise (from calling `then`, `catch` or `finally`) +| **Asynchronous Promise** +| [`createAsyncPromise`](https://nevware21.github.io/ts-async/typedoc/functions/createAsyncPromise.html)
[`createAsyncAllPromise`](https://nevware21.github.io/ts-async/typedoc/functions/createAsyncAllPromise.html)
[`createAsyncRejectedPromise`](https://nevware21.github.io/ts-async/typedoc/functions/createAsyncRejectedPromise.html)
[`createAsyncResolvedPromise`](https://nevware21.github.io/ts-async/typedoc/functions/createAsyncResolvedPromise.html)
[`createAsyncAllSettledPromise`](https://nevware21.github.io/ts-async/typedoc/functions/createAsyncAllSettledPromise.html) | Provides an implementation of the `Promise` contract that uses timeouts to process any chained promises (returned by `then(...)`, `catch(...)`, `finally(...)`), when creating the initial promise you can also provide (override) the default duration of the timeout (defaults to 0ms) to further delay the execution of the chained Promises.
, but can also be provided) to process any chained promises (of any type) +| **Synchronous Promise** +| [`createSyncPromise`](https://nevware21.github.io/ts-async/typedoc/functions/createSyncPromise.html)
[`createSyncAllPromise`](https://nevware21.github.io/ts-async/typedoc/functions/createSyncAllPromise.html)
[`createSyncRejectedPromise`](https://nevware21.github.io/ts-async/typedoc/functions/createSyncRejectedPromise.html)
[`createSyncResolvedPromise`](https://nevware21.github.io/ts-async/typedoc/functions/createSyncResolvedPromise.html)
[`createSyncAllSettledPromise`](https://nevware21.github.io/ts-async/typedoc/functions/createSyncAllSettledPromise.html) | Also implements the `Promise` contract but will immediately execute any chained promises at the point of the original promise getting resolved or rejected, or if already resolved, rejected then at the point of registering the `then`, `catch` or `finally` +| **Idle Promise** +| [`createIdlePromise`](https://nevware21.github.io/ts-async/typedoc/functions/createIdlePromise.html)
[`createIdleAllPromise`](https://nevware21.github.io/ts-async/typedoc/functions/createIdleAllPromise.html)
[`createIdleRejectedPromise`](https://nevware21.github.io/ts-async/typedoc/functions/createIdleRejectedPromise.html)
[`createIdleResolvedPromise`](https://nevware21.github.io/ts-async/typedoc/functions/createIdleResolvedPromise.html)
[`createIdleAllSettledPromise`](https://nevware21.github.io/ts-async/typedoc/functions/createIdleAllSettledPromise.html) | Implements the `Promise` contract and will process any chained promises using the available `requestIdleCallback` (with no timeout by default - but can also be changes by `setDetaultIdlePromiseTimeout`). And when `requestIdleCallback` is not supported this will default to using a timeout via the [`scheduleIdleCallback` from `@nevware21/ts-utils`](https://nevware21.github.io/ts-utils/typedoc/functions/scheduleIdleCallback.html) | **Helpers** +| [`createTimeoutPromise`](https://nevware21.github.io/ts-async/typedoc/functions/createTimeoutPromise.html) | Creates a Promise instance that resolve or reject after the specified timeout. | [`doAwait`](https://nevware21.github.io/ts-async/typedoc/functions/doAwait.html) | Helper which handles `await` "handling" via callback functions to avoid the TypeScript boilerplate code that is added for multiple branches. Internal it handles being passed an `IPromise` or a result value so you avoid needing to test whether the result you have is also a `Promise`.
It takes three (3) optional callback functions for `resolved`, `rejected` and `finally`. | [`doAwaitResponse`](https://nevware21.github.io/ts-async/typedoc/functions/doAwaitResponse.html) | Helper which handles `await` "handling" via a single callback where `resolved` and `rejected` cases are handled by the same callback, this receives an `AwaitResponse` object that provides the `value` or `reason` and a flag indicating whether the Promise was `rejected`) | [`doFinally`](https://nevware21.github.io/ts-async/typedoc/functions/doFinally.html) | Helper to provide `finally` handling for any promise using a callback implementation, analogous to using `try` / `finally` around an `await` function or using the `finally` on the promise directly +| [`arrForEachAsync`](https://nevware21.github.io/ts-async/typedoc/functions/arrForEachAsync.html) | Performs an asynchronous for loop where the calling function may return an [`IPromise`](https://nevware21.github.io/ts-async/typedoc/interfaces/IPromise.html) which must be fulfilled before the next iteration is called. +| [`doWhileAsync`](https://nevware21.github.io/ts-async/typedoc/functions/doWhileAsync.html) | Performs a while loop where the calling function may return an [`IPromise`](https://nevware21.github.io/ts-async/typedoc/interfaces/IPromise.html) which must be fulfilled before the next iteration is called. +| [`iterForOfAsync`](https://nevware21.github.io/ts-async/typedoc/functions/iterForOfAsync.html) | Iterates over the iterator where the calling function may return an [`IPromise`](https://nevware21.github.io/ts-async/typedoc/interfaces/IPromise.html) which must be fulfilled before the next iteration is called. All promise implementations are validated using TypeScript with `async` / `await` and the internal helper functions `doAwait`, `doFinally` and `doAwaitResponse` helpers. Usage of the `doAwait` or `doAwaitResponse` is recommended as this avoids the additional boiler plate code that is added by TypeScript when handling the branches in an `async` / `await` operations, this does however, mean that your calling functions will also need to handle this `async` operations via callbacks rather than just causing the code path to "halt" at the `await` and can therefore may be a little more complex (depending on your implementation). > However, you are NOT restricted to only using `await` OR `doAwait` they can be used together. For example your public API can still be defined as asynchronous, but internally you could use `doAwait` @@ -95,7 +101,7 @@ And then just import the helpers and use them. #### Using Task Scheduler -```TypeScript +```ts import { createTaskScheduler } from "@nevware21/ts-async"; import { scheduleTimeout } from "@nevware21/ts-utils"; @@ -134,7 +140,7 @@ await task1; #### Using Promise Helpers -```TypeScript +```ts import { createPromise } from "@nevware21/ts-async"; import { scheduleTimeout } from "@nevware21/ts-utils"; diff --git a/common/config/rush/npm-shrinkwrap.json b/common/config/rush/npm-shrinkwrap.json index ccf38fc..6e5676c 100644 --- a/common/config/rush/npm-shrinkwrap.json +++ b/common/config/rush/npm-shrinkwrap.json @@ -10,7 +10,7 @@ "dependencies": { "@istanbuljs/nyc-config-typescript": "^1.0.2", "@microsoft/api-extractor": "^7.34.4", - "@nevware21/ts-utils": ">= 0.10.3 < 2.x", + "@nevware21/ts-utils": ">= 0.10.5 < 2.x", "@rollup/plugin-commonjs": "^25.0.0", "@rollup/plugin-json": "^6.0.0", "@rollup/plugin-node-resolve": "^15.0.1", @@ -583,9 +583,9 @@ } }, "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", - "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "engines": { "node": ">=6.0.0" } @@ -935,9 +935,9 @@ "node_modules/@rush-temp/tools-pre-proc": { "version": "0.0.0", "resolved": "file:projects/tools-pre-proc.tgz", - "integrity": "sha512-dx1eS4JEDrq4+oM2ANtUwRufiEit32HWM+2zM/vQvSnSffaC66UQ6+W0NfVBLUf9L7yOdfQlWvTYIjBbBOJcXQ==", + "integrity": "sha512-/rtDdH0X/7/c6/4CBuDehYol+Wk5ukkaQljdBVIpn7NzOWRWOp+BW+zXPG58JjWSWq/aa2H6sqToBNlV9ZvHCg==", "dependencies": { - "@nevware21/ts-utils": ">= 0.10.3 < 2.x", + "@nevware21/ts-utils": ">= 0.10.5 < 2.x", "@types/node": "^18.14.2", "globby": "^11.0.0", "typescript": "^4.9.5" @@ -946,11 +946,11 @@ "node_modules/@rush-temp/ts-async": { "version": "0.0.0", "resolved": "file:projects/ts-async.tgz", - "integrity": "sha512-lSGjxQDws1e79k14vLvwlD+ON+ZK8sZa1+UZAHX/kqxhCOMpvD8SUaYn2/dU5UH5egvBB6uVFA99qY1wQGfXEQ==", + "integrity": "sha512-/m1IGr4nBh7YoW0J6MPFdHskvB3qtSgcXzfByVmdbDhsJVmzHH2lNCeSoSyTpIkh5oZ/WrcWEVifcAioYmnqoQ==", "dependencies": { "@istanbuljs/nyc-config-typescript": "^1.0.2", "@microsoft/api-extractor": "^7.34.4", - "@nevware21/ts-utils": ">= 0.10.3 < 2.x", + "@nevware21/ts-utils": ">= 0.10.5 < 2.x", "@rollup/plugin-commonjs": "^25.0.0", "@rollup/plugin-json": "^6.0.0", "@rollup/plugin-node-resolve": "^15.0.1", @@ -1698,9 +1698,9 @@ } }, "node_modules/browserslist": { - "version": "4.22.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.3.tgz", - "integrity": "sha512-UAp55yfwNv0klWNapjs/ktHoguxuQNGnOzxYmfnXIS+8AsRDZkSDxg7R1AX3GKzn078SBI5dzwzj/Yx0Or0e3A==", + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", + "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", "funding": [ { "type": "opencollective", @@ -1716,8 +1716,8 @@ } ], "dependencies": { - "caniuse-lite": "^1.0.30001580", - "electron-to-chromium": "^1.4.648", + "caniuse-lite": "^1.0.30001587", + "electron-to-chromium": "^1.4.668", "node-releases": "^2.0.14", "update-browserslist-db": "^1.0.13" }, @@ -2693,9 +2693,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/electron-to-chromium": { - "version": "1.4.668", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.668.tgz", - "integrity": "sha512-ZOBocMYCehr9W31+GpMclR+KBaDZOoAEabLdhpZ8oU1JFDwIaFY0UDbpXVEUFc0BIP2O2Qn3rkfCjQmMR4T/bQ==" + "version": "1.4.670", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.670.tgz", + "integrity": "sha512-hcijYOWjOtjKrKPtNA6tuLlA/bTLO3heFG8pQA6mLpq7dRydSWicXova5lyxDzp1iVJaYhK7J2OQlGE52KYn7A==" }, "node_modules/elliptic": { "version": "6.5.4", @@ -3305,6 +3305,19 @@ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -8791,9 +8804,9 @@ } }, "@jridgewell/resolve-uri": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", - "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==" + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==" }, "@jridgewell/set-array": { "version": "1.1.2", @@ -9026,9 +9039,9 @@ }, "@rush-temp/tools-pre-proc": { "version": "file:projects\\tools-pre-proc.tgz", - "integrity": "sha512-dx1eS4JEDrq4+oM2ANtUwRufiEit32HWM+2zM/vQvSnSffaC66UQ6+W0NfVBLUf9L7yOdfQlWvTYIjBbBOJcXQ==", + "integrity": "sha512-/rtDdH0X/7/c6/4CBuDehYol+Wk5ukkaQljdBVIpn7NzOWRWOp+BW+zXPG58JjWSWq/aa2H6sqToBNlV9ZvHCg==", "requires": { - "@nevware21/ts-utils": ">= 0.10.3 < 2.x", + "@nevware21/ts-utils": ">= 0.10.5 < 2.x", "@types/node": "^18.14.2", "globby": "^11.0.0", "typescript": "^4.9.5" @@ -9036,11 +9049,11 @@ }, "@rush-temp/ts-async": { "version": "file:projects\\ts-async.tgz", - "integrity": "sha512-lSGjxQDws1e79k14vLvwlD+ON+ZK8sZa1+UZAHX/kqxhCOMpvD8SUaYn2/dU5UH5egvBB6uVFA99qY1wQGfXEQ==", + "integrity": "sha512-/m1IGr4nBh7YoW0J6MPFdHskvB3qtSgcXzfByVmdbDhsJVmzHH2lNCeSoSyTpIkh5oZ/WrcWEVifcAioYmnqoQ==", "requires": { "@istanbuljs/nyc-config-typescript": "^1.0.2", "@microsoft/api-extractor": "^7.34.4", - "@nevware21/ts-utils": ">= 0.10.3 < 2.x", + "@nevware21/ts-utils": ">= 0.10.5 < 2.x", "@rollup/plugin-commonjs": "^25.0.0", "@rollup/plugin-json": "^6.0.0", "@rollup/plugin-node-resolve": "^15.0.1", @@ -9669,12 +9682,12 @@ } }, "browserslist": { - "version": "4.22.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.3.tgz", - "integrity": "sha512-UAp55yfwNv0klWNapjs/ktHoguxuQNGnOzxYmfnXIS+8AsRDZkSDxg7R1AX3GKzn078SBI5dzwzj/Yx0Or0e3A==", + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", + "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", "requires": { - "caniuse-lite": "^1.0.30001580", - "electron-to-chromium": "^1.4.648", + "caniuse-lite": "^1.0.30001587", + "electron-to-chromium": "^1.4.668", "node-releases": "^2.0.14", "update-browserslist-db": "^1.0.13" } @@ -10389,9 +10402,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "electron-to-chromium": { - "version": "1.4.668", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.668.tgz", - "integrity": "sha512-ZOBocMYCehr9W31+GpMclR+KBaDZOoAEabLdhpZ8oU1JFDwIaFY0UDbpXVEUFc0BIP2O2Qn3rkfCjQmMR4T/bQ==" + "version": "1.4.670", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.670.tgz", + "integrity": "sha512-hcijYOWjOtjKrKPtNA6tuLlA/bTLO3heFG8pQA6mLpq7dRydSWicXova5lyxDzp1iVJaYhK7J2OQlGE52KYn7A==" }, "elliptic": { "version": "6.5.4", @@ -10850,6 +10863,12 @@ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, + "fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "optional": true + }, "function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", diff --git a/common/scripts/install-run.js b/common/scripts/install-run.js index bf89cd2..11bb97c 100644 --- a/common/scripts/install-run.js +++ b/common/scripts/install-run.js @@ -42,12 +42,13 @@ __webpack_require__.r(__webpack_exports__); */ // create a global _combinedNpmrc for cache purpose const _combinedNpmrcMap = new Map(); -function _trimNpmrcFile(sourceNpmrcPath) { +function _trimNpmrcFile(sourceNpmrcPath, extraLines = []) { const combinedNpmrcFromCache = _combinedNpmrcMap.get(sourceNpmrcPath); if (combinedNpmrcFromCache !== undefined) { return combinedNpmrcFromCache; } let npmrcFileLines = fs__WEBPACK_IMPORTED_MODULE_0__.readFileSync(sourceNpmrcPath).toString().split('\n'); + npmrcFileLines.push(...extraLines); npmrcFileLines = npmrcFileLines.map((line) => (line || '').trim()); const resultLines = []; // This finds environment variable tokens that look like "${VAR_NAME}" @@ -106,10 +107,10 @@ function _trimNpmrcFile(sourceNpmrcPath) { * @returns * The text of the the .npmrc with lines containing undefined variables commented out. */ -function _copyAndTrimNpmrcFile(logger, sourceNpmrcPath, targetNpmrcPath) { +function _copyAndTrimNpmrcFile(logger, sourceNpmrcPath, targetNpmrcPath, extraLines) { logger.info(`Transforming ${sourceNpmrcPath}`); // Verbose logger.info(` --> "${targetNpmrcPath}"`); - const combinedNpmrc = _trimNpmrcFile(sourceNpmrcPath); + const combinedNpmrc = _trimNpmrcFile(sourceNpmrcPath, extraLines); fs__WEBPACK_IMPORTED_MODULE_0__.writeFileSync(targetNpmrcPath, combinedNpmrc); return combinedNpmrc; } @@ -127,12 +128,16 @@ function syncNpmrc(sourceNpmrcFolder, targetNpmrcFolder, useNpmrcPublish, logger info: console.log, // eslint-disable-next-line no-console error: console.error -}) { +}, extraLines) { const sourceNpmrcPath = path__WEBPACK_IMPORTED_MODULE_1__.join(sourceNpmrcFolder, !useNpmrcPublish ? '.npmrc' : '.npmrc-publish'); const targetNpmrcPath = path__WEBPACK_IMPORTED_MODULE_1__.join(targetNpmrcFolder, '.npmrc'); try { if (fs__WEBPACK_IMPORTED_MODULE_0__.existsSync(sourceNpmrcPath)) { - return _copyAndTrimNpmrcFile(logger, sourceNpmrcPath, targetNpmrcPath); + // Ensure the target folder exists + if (!fs__WEBPACK_IMPORTED_MODULE_0__.existsSync(targetNpmrcFolder)) { + fs__WEBPACK_IMPORTED_MODULE_0__.mkdirSync(targetNpmrcFolder, { recursive: true }); + } + return _copyAndTrimNpmrcFile(logger, sourceNpmrcPath, targetNpmrcPath, extraLines); } else if (fs__WEBPACK_IMPORTED_MODULE_0__.existsSync(targetNpmrcPath)) { // If the source .npmrc doesn't exist and there is one in the target, delete the one in the target diff --git a/lib/package.json b/lib/package.json index 0382ce2..b95748d 100644 --- a/lib/package.json +++ b/lib/package.json @@ -74,7 +74,7 @@ }, "dependencies": { - "@nevware21/ts-utils": ">= 0.10.3 < 2.x" + "@nevware21/ts-utils": ">= 0.10.5 < 2.x" }, "devDependencies": { "@nevware21/tools-pre-proc": "0.1.0", diff --git a/lib/rollup.config.js b/lib/rollup.config.js index 1a63a97..92174c1 100644 --- a/lib/rollup.config.js +++ b/lib/rollup.config.js @@ -87,7 +87,7 @@ const rollupConfigFactory = (srcPath, destPath, isMinified, path, format = "iife const taskRollupConfig = { input: `./${srcPath}/index.js`, output: { - file: `./dist/${destPath}/${path}/${outputName}${postfix}.js`, + file: `./bundle/${destPath}/${path}/${outputName}${postfix}.js`, banner: banner, format: format, name: "nevware21.ts-async", @@ -112,7 +112,7 @@ const rollupConfigFactory = (srcPath, destPath, isMinified, path, format = "iife }; if (isMinified) { - taskRollupConfig.output.file = `./dist/${destPath}/${path}/${outputName}${postfix}.min.js`; + taskRollupConfig.output.file = `./bundle/${destPath}/${path}/${outputName}${postfix}.min.js`; if (format !== "esm") { taskRollupConfig.plugins.push( uglify3({ @@ -215,7 +215,7 @@ const polyfillRollupConfigFactory = (srcPath, destPath, isMinified, format = "ii const taskRollupConfig = { input: `./${srcPath}/polyfills.js`, output: { - file: `./dist/${destPath}/${polyFillOutputName}${postfix}.js`, + file: `./bundle/${destPath}/${polyFillOutputName}${postfix}.js`, banner: polyFillBanner, format: format, name: "nevware21.ts-async", @@ -239,7 +239,7 @@ const polyfillRollupConfigFactory = (srcPath, destPath, isMinified, format = "ii }; if (isMinified) { - taskRollupConfig.output.file = `./dist/${destPath}/${polyFillOutputName}${postfix}.min.js`; + taskRollupConfig.output.file = `./bundle/${destPath}/${polyFillOutputName}${postfix}.min.js`; taskRollupConfig.plugins.push( uglify3({ ie8: false, @@ -271,27 +271,27 @@ export default [ rollupConfigFactory("dist-es5", "es5", false, "esm", "esm"), rollupConfigFactory("dist-es5", "es5", true, "esm", "esm"), - rollupConfigFactory("dist-es5", "es5", false, "amd", "amd"), - rollupConfigFactory("dist-es5", "es5", true, "amd", "amd"), - rollupConfigFactory("dist-es5", "es5", false, "cjs", "cjs"), - rollupConfigFactory("dist-es5", "es5", true, "cjs", "cjs"), + // rollupConfigFactory("dist-es5", "es5", false, "amd", "amd"), + // rollupConfigFactory("dist-es5", "es5", true, "amd", "amd"), + // rollupConfigFactory("dist-es5", "es5", false, "cjs", "cjs"), + // rollupConfigFactory("dist-es5", "es5", true, "cjs", "cjs"), rollupConfigFactory("dist-es5", "es5", false, "iife", "iife"), rollupConfigFactory("dist-es5", "es5", true, "iife", "iife"), rollupConfigFactory("dist-es5", "es5", false, "umd", "umd"), rollupConfigFactory("dist-es5", "es5", true, "umd", "umd"), - rollupConfigFactory("dist-es5", "es5", false, "system", "system"), - rollupConfigFactory("dist-es5", "es5", true, "system", "system"), + // rollupConfigFactory("dist-es5", "es5", false, "system", "system"), + // rollupConfigFactory("dist-es5", "es5", true, "system", "system"), rollupConfigFactory("dist-es6", "es6", false, "esm", "esm"), rollupConfigFactory("dist-es6", "es6", true, "esm", "esm"), - rollupConfigFactory("dist-es6", "es6", false, "amd", "amd"), - rollupConfigFactory("dist-es6", "es6", true, "amd", "amd"), - rollupConfigFactory("dist-es6", "es6", false, "cjs", "cjs"), - rollupConfigFactory("dist-es6", "es6", true, "cjs", "cjs"), + // rollupConfigFactory("dist-es6", "es6", false, "amd", "amd"), + // rollupConfigFactory("dist-es6", "es6", true, "amd", "amd"), + // rollupConfigFactory("dist-es6", "es6", false, "cjs", "cjs"), + // rollupConfigFactory("dist-es6", "es6", true, "cjs", "cjs"), rollupConfigFactory("dist-es6", "es6", false, "iife", "iife"), rollupConfigFactory("dist-es6", "es6", true, "iife", "iife"), rollupConfigFactory("dist-es6", "es6", false, "umd", "umd"), - rollupConfigFactory("dist-es6", "es6", true, "umd", "umd"), - rollupConfigFactory("dist-es6", "es6", false, "system", "system"), - rollupConfigFactory("dist-es6", "es6", true, "system", "system") + rollupConfigFactory("dist-es6", "es6", true, "umd", "umd") + // rollupConfigFactory("dist-es6", "es6", false, "system", "system"), + // rollupConfigFactory("dist-es6", "es6", true, "system", "system") ]; diff --git a/lib/src/helpers/doWhileAsync.ts b/lib/src/helpers/doWhileAsync.ts index 9f4cbf1..9edf885 100644 --- a/lib/src/helpers/doWhileAsync.ts +++ b/lib/src/helpers/doWhileAsync.ts @@ -6,14 +6,14 @@ * Licensed under the MIT license. */ -import { fnCall, isFunction, isPromiseLike, utcNow } from "@nevware21/ts-utils"; +import { isFunction, isPromiseLike, utcNow } from "@nevware21/ts-utils"; import { IPromise } from "../interfaces/IPromise"; import { createPromise } from "../promise/promise"; import { doAwait } from "../promise/await"; import { RejectPromiseHandler, ResolvePromiseHandler } from "../interfaces/types"; import { IWhileState } from "../interfaces/IWhileState"; -const _doneChk = (isDone: boolean, state: IWhileState, value: T, thisArg?: any) => { +const _doneChk = /*#__PURE__*/(isDone: boolean, state: IWhileState, value: T, thisArg?: any) => { let result: boolean | IPromise = isDone; state.res = value; if (!result) { @@ -185,7 +185,7 @@ const _doneChk = (isDone: boolean, state: IWhileState, value: T, thisArg?: * console.log(result); // my old friend * ``` */ -export const doWhileAsync = (callbackFn: (state: IWhileState) => T | IPromise, isDoneFn?: (state: IWhileState) => boolean | void | IPromise, thisArg?: any): T | IPromise => { +export function doWhileAsync(callbackFn: (state: IWhileState) => T | IPromise, isDoneFn?: (state: IWhileState) => boolean | void | IPromise, thisArg?: any): T | IPromise { let promise: T | IPromise; let resolve: ResolvePromiseHandler; let reject: RejectPromiseHandler | never = (reason: any) => { diff --git a/lib/src/helpers/iterForOfAsync.ts b/lib/src/helpers/iterForOfAsync.ts index c6e64eb..20de57f 100644 --- a/lib/src/helpers/iterForOfAsync.ts +++ b/lib/src/helpers/iterForOfAsync.ts @@ -6,15 +6,15 @@ * Licensed under the MIT license. */ -import { ILazyValue, WellKnownSymbols, fnCall, getKnownSymbol, getLazy, isIterator, isPromiseLike } from "@nevware21/ts-utils"; +import { ICachedValue, WellKnownSymbols, createCachedValue, fnCall, getKnownSymbol, isIterator, isPromiseLike } from "@nevware21/ts-utils"; import { IPromise } from "../interfaces/IPromise"; import { doWhileAsync } from "./doWhileAsync"; import { IWhileState } from "../interfaces/IWhileState"; import { DONE, RETURN, VALUE } from "../internal/constants"; -import { doAwait } from "../promise/await"; +import { doAwait, doFinally } from "../promise/await"; -let _iterSymbol: ILazyValue; -let _iterAsyncSymbol: ILazyValue; +let _iterSymbol: ICachedValue; +let _iterAsyncSymbol: ICachedValue; /** * Calls the provided `callbackFn` function once for each element in the iterator or iterator returned by @@ -78,45 +78,46 @@ let _iterAsyncSymbol: ILazyValue; * }); */ export function iterForOfAsync(iter: Iterator | Iterable | AsyncIterator | AsyncIterable, callbackFn: (value: T, count: number, iter?: Iterator | AsyncIterator) => void | number | IPromise, thisArg?: any): void | number | IPromise { + let err: { e: any }; + let iterResult: IteratorResult; + let theIter: AsyncIterator | Iterator = iter as AsyncIterator | Iterator; + + function onFailed(failed: any): never { + 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) { + // eslint-disable-next-line no-unsafe-finally + throw err.e; + } + } + } + if (iter) { - let theIter: AsyncIterator | Iterator = iter as AsyncIterator | Iterator; if (!isIterator(iter)) { // Get the asyncIterator from the iterable - !_iterAsyncSymbol && (_iterAsyncSymbol = getLazy(() => getKnownSymbol(WellKnownSymbols.asyncIterator))); + !_iterAsyncSymbol && (_iterAsyncSymbol = createCachedValue(getKnownSymbol(WellKnownSymbols.asyncIterator))); theIter = iter[_iterAsyncSymbol.v] ? iter[_iterAsyncSymbol.v]() : null; if (!theIter) { // Get the iterator from the iterable - !_iterSymbol && (_iterSymbol = getLazy(() => getKnownSymbol(WellKnownSymbols.iterator))); + !_iterSymbol && (_iterSymbol = createCachedValue(getKnownSymbol(WellKnownSymbols.iterator))); theIter = iter[_iterSymbol.v] ? iter[_iterSymbol.v]() : null; } } if (theIter && isIterator(theIter)) { - let err: { e: any }; - let iterResult: IteratorResult; - - const onFailed = (failed: any): never => { - err = { e: failed }; - if (theIter.throw) { - iterResult = null; - theIter.throw(err); - } - - throw failed; - }; - - const onFinally = () => { - try { - if (iterResult && !iterResult[DONE]) { - theIter[RETURN] && theIter[RETURN](iterResult); - } - } finally { - if (err) { - // eslint-disable-next-line no-unsafe-finally - throw err.e; - } - } - }; let result: void | number | IPromise; try { @@ -138,7 +139,7 @@ export function iterForOfAsync(iter: Iterator | Iterable | AsyncI }, thisArg || theIter); if (isPromiseLike(result)) { - result = result.catch(onFailed).finally(onFinally); + result = doFinally(result.catch(onFailed), onFinally); } return result; diff --git a/lib/src/index.ts b/lib/src/index.ts index 99cf002..85aa149 100644 --- a/lib/src/index.ts +++ b/lib/src/index.ts @@ -10,6 +10,7 @@ export { AwaitResponse } from "./interfaces/await-response"; export { IPromise } from "./interfaces/IPromise"; export { ITaskScheduler } from "./interfaces/ITaskScheduler"; export { IWhileState } from "./interfaces/IWhileState"; +export { IPromiseResult } from "./interfaces/IPromiseResult"; export { ResolvedPromiseHandler, RejectedPromiseHandler, FinallyPromiseHandler, ResolvePromiseHandler, RejectPromiseHandler, PromiseExecutor, PromiseCreatorFn, StartQueuedTaskFn @@ -17,20 +18,23 @@ export { export { doAwaitResponse, doAwait, doFinally } from "./promise/await"; export { setPromiseDebugState } from "./promise/debug"; export { - createNativePromise, createNativeAllPromise, createNativeResolvedPromise, createNativeRejectedPromise + createNativePromise, createNativeAllPromise, createNativeResolvedPromise, createNativeRejectedPromise, + createNativeAllSettledPromise } from "./promise/nativePromise"; export { - createSyncPromise, createSyncAllPromise, createSyncResolvedPromise, createSyncRejectedPromise + createSyncPromise, createSyncAllPromise, createSyncResolvedPromise, createSyncRejectedPromise, + createSyncAllSettledPromise } from "./promise/syncPromise"; export { createIdlePromise, createIdleAllPromise, createIdleResolvedPromise, createIdleRejectedPromise, - setDefaultIdleTimeout + createIdleAllSettledPromise, setDefaultIdleTimeout } from "./promise/idlePromise"; export { - createAsyncPromise, createAsyncAllPromise, createAsyncResolvedPromise, createAsyncRejectedPromise + createAsyncPromise, createAsyncAllPromise, createAsyncResolvedPromise, createAsyncRejectedPromise, + createAsyncAllSettledPromise } from "./promise/asyncPromise"; export { - createPromise, createAllPromise, createRejectedPromise, createResolvedPromise, + createPromise, createAllPromise, createRejectedPromise, createResolvedPromise, createAllSettledPromise, setCreatePromiseImpl } from "./promise/promise"; diff --git a/lib/src/interfaces/IPromiseResult.ts b/lib/src/interfaces/IPromiseResult.ts new file mode 100644 index 0000000..46a25e8 --- /dev/null +++ b/lib/src/interfaces/IPromiseResult.ts @@ -0,0 +1,44 @@ +/* + * @nevware21/ts-async + * https://github.com/nevware21/ts-async + * + * Copyright (c) 2024 Nevware21 + * Licensed under the MIT license. + */ + +/** + * The result of a promise. It can either be fulfilled with a value, or rejected with a reason. + * @since 0.5.0 + * @group Promise + * @typeParam T - The type of the fulfilled value. + * @typeParam U - The type of the rejected reason. + * + * @example + * ```ts + * const result: IPromiseResult = { + * status: "fulfilled", + * value: 42 + * }; + * + * const result: IPromiseResult = { + * status: "rejected", + * reason: "Hello Darkness" + * }; + * ``` + */ +export interface IPromiseResult { + /** + * A string indicating whether the promise was fulfilled or rejected + */ + status: "fulfilled" | "rejected"; + + /** + * The value that the promise was fulfilled with. + */ + value?: T; + + /** + * The reason that the promise was rejected with. + */ + reason?: any; +} diff --git a/lib/src/interfaces/await-response.ts b/lib/src/interfaces/await-response.ts index aecadeb..fd5639d 100644 --- a/lib/src/interfaces/await-response.ts +++ b/lib/src/interfaces/await-response.ts @@ -7,21 +7,49 @@ */ /** - * Simple interface to convert a promise then (resolve/reject) into a single response + * A Simple type which identifies the result of a promise as a single response, it identifies + * if the promise was rejected or resolved along with the resolved value or rejected reason. + * It is a union of the `IPromiseFulfilledResult` and `IPromiseRejectedResult` interfaces the + * response will contain the `rejected` property which will be true if the promise was rejected + * or false if the promise was resolved. The `status` property will be set to either "fulfilled" + * or "rejected" to identify the status of the promise. The `value` or `reason` properties will + * contain the resolved value or rejected reason respectively. + * + * @group Promise + * @typeParam T - The type of the fulfilled value. + * + * @example + * ```ts + * const result: AwaitResponse = { + * status: "fulfilled", + * value: 42 + * }; + * + * const result: AwaitResponse = { + * rejected: true, + * status: "rejected", + * reason: "Hello Darkness" + * }; + * ``` */ -export interface AwaitResponse { +export interface AwaitResponse { /** - * The value returned by the resolved promise + * A string indicating that the promise was rejected. */ - value?: T; + status: "fulfilled" | "rejected"; /** - * Identifies if the promise was rejected (true) or was resolved (false/undefined) + * The value that the promise was fulfilled with. */ - rejected?: boolean; + value?: T; - /** - * The reason returned when the promise rejected + /** + * The reason that the promise was rejected with. */ - reason?: any; + reason?: R; + + /** + * Identifies if the promise was rejected (true) or was resolved (false/undefined) + */ + rejected?: boolean; } diff --git a/lib/src/internal/constants.ts b/lib/src/internal/constants.ts index f4ad190..871206d 100644 --- a/lib/src/internal/constants.ts +++ b/lib/src/internal/constants.ts @@ -10,4 +10,5 @@ export const STR_PROMISE = "Promise"; export const DONE = "done"; export const VALUE = "value"; export const ITERATOR = "iterator"; -export const RETURN = "return"; \ No newline at end of file +export const RETURN = "return"; +export const REJECTED = "rejected"; \ No newline at end of file diff --git a/lib/src/internal/state.ts b/lib/src/internal/state.ts index bd25e81..82851a9 100644 --- a/lib/src/internal/state.ts +++ b/lib/src/internal/state.ts @@ -6,6 +6,8 @@ * Licensed under the MIT license. */ +import { REJECTED } from "./constants"; + /** * @ignore -- Don't include in the generated documentation * @internal @@ -21,6 +23,6 @@ export const enum ePromiseState { * @ignore -- Don't include in the generated documentation * @internal */ -export const STRING_STATES: string[] = [ - "pending", "resolving", "resolved", "rejected" +export const STRING_STATES: string[] = /*#__PURE__*/[ + "pending", "resolving", "resolved", REJECTED ]; diff --git a/lib/src/polyfills.ts b/lib/src/polyfills.ts index 68146d5..704d788 100644 --- a/lib/src/polyfills.ts +++ b/lib/src/polyfills.ts @@ -6,7 +6,7 @@ * Licensed under the MIT license. */ -import { createAsyncAllPromise, createAsyncRejectedPromise, createAsyncResolvedPromise } from "./promise/asyncPromise"; +import { createAsyncAllPromise, createAsyncAllSettledPromise, createAsyncRejectedPromise, createAsyncResolvedPromise } from "./promise/asyncPromise"; import { objForEachKey } from "@nevware21/ts-utils"; import { PolyPromise } from "./polyfills/promise"; @@ -16,7 +16,8 @@ declare var Promise: any; const promisePolyfills = { "all": createAsyncAllPromise, "resolved": createAsyncResolvedPromise, - "rejected": createAsyncRejectedPromise + "rejected": createAsyncRejectedPromise, + "allSettled": createAsyncAllSettledPromise }; if (!Promise) { diff --git a/lib/src/polyfills/promise.ts b/lib/src/polyfills/promise.ts index 2b72c2c..a5af12d 100644 --- a/lib/src/polyfills/promise.ts +++ b/lib/src/polyfills/promise.ts @@ -7,7 +7,7 @@ */ import { getKnownSymbol, objDefineProp, WellKnownSymbols } from "@nevware21/ts-utils"; -import { createAsyncAllPromise, createAsyncPromise, createAsyncRejectedPromise, createAsyncResolvedPromise } from "../promise/asyncPromise"; +import { createAsyncAllPromise, createAsyncAllSettledPromise, createAsyncPromise, createAsyncRejectedPromise, createAsyncResolvedPromise } from "../promise/asyncPromise"; import { IPromise } from "../interfaces/IPromise"; import { PromiseExecutor } from "../interfaces/types"; @@ -64,9 +64,25 @@ export interface PolyPromiseConstructor { * @returns A promise whose internal state matches the provided promise. */ resolve(value: T | PromiseLike): Promise; + + /** + * Creates a Promise that is resolved with an array of results when all + * of the provided Promises resolve or reject. + * @param values An array of Promises. + * @returns A new Promise. + */ + allSettled(values: T): Promise<{ -readonly [P in keyof T]: PromiseSettledResult>; }>; + + /** + * Creates a Promise that is resolved with an array of results when all + * of the provided Promises resolve or reject. + * @param values An array of Promises. + * @returns A new Promise. + */ + allSettled(values: Iterable>): Promise>[]>; } -export let PolyPromise = (function () { +export let PolyPromise = /*#__PURE__*/(function () { function PolyPromiseImpl(executor: PromiseExecutor) { this._$ = createAsyncPromise(executor); if (toStringTagSymbol) { @@ -83,6 +99,7 @@ export let PolyPromise = (function () { //PolyPromiseImpl.race = createAsyncRacePromise; PolyPromiseImpl.reject = createAsyncRejectedPromise; PolyPromiseImpl.resolve = createAsyncResolvedPromise; + PolyPromiseImpl.allSettled = createAsyncAllSettledPromise; let theProto = PolyPromiseImpl.prototype; theProto.then = function (onResolved: any, onRejected: any) { return this._$.then(onResolved, onRejected); diff --git a/lib/src/promise/asyncPromise.ts b/lib/src/promise/asyncPromise.ts index 4317638..e7fb096 100644 --- a/lib/src/promise/asyncPromise.ts +++ b/lib/src/promise/asyncPromise.ts @@ -6,10 +6,14 @@ * Licensed under the MIT license. */ -import { _createAllPromise, _createPromise, _createRejectedPromise, _createResolvedPromise } from "./base"; +import { _createAllPromise, _createAllSettledPromise, _createPromise, _createRejectedPromise, _createResolvedPromise } from "./base"; import { IPromise } from "../interfaces/IPromise"; import { timeoutItemProcessor } from "./itemProcessor"; import { PromiseExecutor } from "../interfaces/types"; +import { IPromiseResult } from "../interfaces/IPromiseResult"; +import { ICachedValue } from "@nevware21/ts-utils"; + +let _allAsyncSettledCreator: ICachedValue<(input: T, timeout?: number) => IPromise<{ -readonly [P in keyof T]: IPromiseResult>; }>>; /** * Creates an asynchronous Promise instance that when resolved or rejected will execute it's pending chained operations @@ -33,6 +37,7 @@ export function createAsyncPromise(executor: PromiseExecutor, timeout?: nu * When resolved or rejected any additional chained operations will execute __asynchronously__ using the optional * timeout value to schedul when the chained item will be executed (eg. `then()`; `catch()`; `finally()`). * @group Async + * @group Promise * @group All * @param input - The array of promises to wait to be resolved / rejected before resolving or rejecting the new promise * @param timeout @@ -44,7 +49,7 @@ export function createAsyncPromise(executor: PromiseExecutor, timeout?: nu * promises reject. * */ -export const createAsyncAllPromise: (input: PromiseLike[], timeout?: number) => IPromise = _createAllPromise(createAsyncPromise); +export const createAsyncAllPromise: (input: Iterable>, timeout?: number) => IPromise = /*#__PURE__*/_createAllPromise(createAsyncPromise); // /** // * Creates a Promise that is resolved or rejected when any of the provided Promises are resolved @@ -61,19 +66,100 @@ export const createAsyncAllPromise: (input: PromiseLike[], timeout?: numbe * If a new instance is returned then any chained operations will execute __asynchronously__ using the optional * timeout value to schedule when the chained items will be executed.(eg. `then()`; `finally()`). * @group Async + * @group Promise * @group Resolved * @param value - The value to be used by this `Promise`. Can also be a `Promise` or a thenable to resolve. * @param timeout - Optional timeout to wait before processing the items, defaults to zero. */ -export const createAsyncResolvedPromise: (value: T, timeout?: number) => IPromise = _createResolvedPromise(createAsyncPromise); +export const createAsyncResolvedPromise: (value: T, timeout?: number) => IPromise = /*#__PURE__*/_createResolvedPromise(createAsyncPromise); /** * Returns a single asynchronous Promise instance that is already rejected with the given reason. * Any chained operations will execute __asynchronously__ using the optional timeout value to schedule * when then chained items will be executed. (eg. `catch()`; `finally()`). * @group Async + * @group Promise * @group Rejected * @param reason - The rejection reason * @param timeout - Optional timeout to wait before processing the items, defaults to zero. */ -export const createAsyncRejectedPromise: (reason: any, timeout?: number) => IPromise = _createRejectedPromise(createAsyncPromise); +export const createAsyncRejectedPromise: (reason: any, timeout?: number) => IPromise = /*#__PURE__*/_createRejectedPromise(createAsyncPromise); + +/** + * Returns a single Promise instance that resolves to an array of the results from the input promises. + * This returned promise will resolve and execute it's pending chained operations based on the + * {@link createAsyncPromise Aasynchronous} promise implementation. Any chained operations will execute + * __asynchronously__ when the final operation pending promises have resolved, or if the input contains + * no promises. It will resolve only after all of the input promises have either resolved or rejected, + * and will resolve with an array of {@link IPromiseResult } objects that each describe the outcome of + * each promise. + * @since 0.5.0 + * @group Async + * @group Promise + * @group AllSettled + * @param values - The iterator of promises to wait to be resolved / rejected before resolving or rejecting the new promise + * @param timeout - Optional timeout to wait before processing the items, defaults to zero, only used when Native promises are not available. + * @returns A pending `Promise` that will resolve to an array of {@link IPromiseResult } objects that each describe the outcome of each promise. + * + * @example + * ```ts + * const promises = [ + * createResolvedPromise(1), + * createResolvedPromise(2), + * createResolvedPromise(3), + * createRejectedPromise("error"), + * ]; + * + * const results = await createAllSettledPromise(promises); + * + * // results is: + * // [ + * // { status: "fulfilled", value: 1 }, + * // { status: "fulfilled", value: 2 }, + * // { status: "fulfilled", value: 3 }, + * // { status: "rejected", reason: "error" } + * // ] + * ``` + */ +export function createAsyncAllSettledPromise(values: Iterable> | Iterator>, timeout?: number): IPromise>[]>; + +/** + * Returns a single Promise instance that resolves to an array of the results from the input promises. + * This returned promise will resolve and execute it's pending chained operations based on the + * {@link createAsyncPromise Aasynchronous} promise implementation. Any chained operations will execute + * __asynchronously__ when the final operation pending promises have resolved, or if the input contains + * no promises. It will resolve only after all of the input promises have either resolved or rejected, + * and will resolve with an array of {@link IPromiseResult } objects that each describe the outcome of + * each promise. + * @since 0.5.0 + * @group Async + * @group Promise + * @group AllSettled + * @param input - An array of promises to wait to be resolved / rejected before resolving or rejecting the new promise + * @param timeout - Optional timeout to wait before processing the items, defaults to zero, only used when Native promises are not available. + * @returns A pending `Promise` that will resolve to an array of {@link IPromiseResult } objects that each describe the outcome of each promise. + * + * @example + * ```ts + * const promises = [ + * createResolvedPromise(1), + * createResolvedPromise(2), + * createResolvedPromise(3), + * createRejectedPromise("error"), + * ]; + * + * const results = await createAllSettledPromise(promises); + * + * // results is: + * // [ + * // { status: "fulfilled", value: 1 }, + * // { status: "fulfilled", value: 2 }, + * // { status: "fulfilled", value: 3 }, + * // { status: "rejected", reason: "error" } + * // ] + * ``` + */ +export function createAsyncAllSettledPromise(input: T, timeout?: number): IPromise<{ -readonly [P in keyof T]: IPromiseResult>; }> { + !_allAsyncSettledCreator && (_allAsyncSettledCreator = _createAllSettledPromise(createAsyncPromise)); + return _allAsyncSettledCreator.v(input, timeout); +} diff --git a/lib/src/promise/await.ts b/lib/src/promise/await.ts index 3542c7e..ddfdf88 100644 --- a/lib/src/promise/await.ts +++ b/lib/src/promise/await.ts @@ -10,6 +10,7 @@ import { isPromiseLike } from "@nevware21/ts-utils"; import { AwaitResponse } from "../interfaces/await-response"; import { IPromise } from "../interfaces/IPromise"; import { FinallyPromiseHandler, RejectedPromiseHandler, ResolvedPromiseHandler } from "../interfaces/types"; +import { REJECTED } from "../internal/constants"; /** * Helper to coallesce the promise resolved / reject into a single callback to simplify error handling. @@ -126,12 +127,14 @@ export function doAwaitResponse(value: T | Pr export function doAwaitResponse(value: T | IPromise, cb: (response: AwaitResponse) => T | TResult1 | TResult2 | IPromise): T | TResult1 | TResult2 | IPromise { return doAwait(value as T, (value) => { return cb ? cb({ - value: value, - rejected: false + status: "fulfilled", + rejected: false, + value: value }) : value; }, (reason) => { return cb ? cb({ + status: REJECTED, rejected: true, reason: reason }) : reason; diff --git a/lib/src/promise/base.ts b/lib/src/promise/base.ts index 953fa1c..d24c4e3 100644 --- a/lib/src/promise/base.ts +++ b/lib/src/promise/base.ts @@ -7,11 +7,12 @@ */ import { - arrForEach, arrSlice, dumpObj, getKnownSymbol, hasSymbol, isFunction, isPromiseLike, isUndefined, + arrSlice, dumpObj, getKnownSymbol, hasSymbol, isFunction, isPromiseLike, isUndefined, throwTypeError, WellKnownSymbols, objToString, scheduleTimeout, ITimerHandler, getWindow, isNode, - getGlobal, ILazyValue, objDefine, objDefineProp, lazySafeGetInst + getGlobal, ILazyValue, objDefine, objDefineProp, lazySafeGetInst, iterForOf, isIterator, isIterable, + isArray, arrForEach, createCachedValue, ICachedValue } from "@nevware21/ts-utils"; -import { doAwait } from "./await"; +import { doAwait, doAwaitResponse } from "./await"; import { _addDebugState, _promiseDebugEnabled } from "./debug"; import { IPromise } from "../interfaces/IPromise"; import { PromisePendingProcessor } from "./itemProcessor"; @@ -20,7 +21,8 @@ import { } from "../interfaces/types"; import { ePromiseState, STRING_STATES } from "../internal/state"; import { emitEvent } from "./event"; -import { STR_PROMISE } from "../internal/constants"; +import { REJECTED, STR_PROMISE } from "../internal/constants"; +import { IPromiseResult } from "../interfaces/IPromiseResult"; //#ifdef DEBUG import { _debugLog } from "./debug"; @@ -311,15 +313,15 @@ export function _createPromise(newPromise: PromiseCreatorFn, processor: Promi * @param newPromise - The delegate function used to create a new promise object the new promise instance. * @returns A function to create a promise that will be resolved when all arguments are resolved. */ -export function _createAllPromise(newPromise: PromiseCreatorFn): (input: PromiseLike[], ...additionalArgs: any) => IPromise { - return function (input: PromiseLike[]): IPromise { +export function _createAllPromise(newPromise: PromiseCreatorFn): (input: Iterable>, ...additionalArgs: any) => IPromise[]> { + return function (input: Iterable>): IPromise[]> { let additionalArgs = arrSlice(arguments, 1); - return newPromise((resolve, reject) => { + return newPromise[]>((resolve, reject) => { try { let values = [] as any; let pending = 1; // Prefix to 1 so we finish iterating over all of the input promises first - arrForEach(input, (item, idx) => { + iterForOf(input, (item, idx) => { if (item) { pending++; doAwait(item, (value) => { @@ -387,3 +389,63 @@ export function _createRejectedPromise(newPromise: PromiseCreatorFn): (reason }, additionalArgs); }; } + +/** + * @ignore + * @internal + * @since 0.5.0 + * Returns a function which when called will return a new Promise object that resolves to an array of + * IPromiseResults from the input promises. The returned promise will resolve when all of the inputs' + * promises have resolved or rejected, or if the input contains no promises. It will resolve only after + * all input promises have been fulfilled (resolve or rejected). + * @param newPromise - The delegate function used to create a new promise object the new promise instance. + * @returns A function to create a promise that will be resolved when all arguments are resolved. + */ +export function _createAllSettledPromise(newPromise: PromiseCreatorFn, ..._args: any[]): ICachedValue<(input: T, timeout?: number) => IPromise<{ -readonly [P in keyof T]: IPromiseResult>; }>> { + return createCachedValue(function (input: T, ..._args: any[]): IPromise<{ -readonly [P in keyof T]: IPromiseResult>; }> { + let additionalArgs = arrSlice(arguments, 1); + return newPromise<{ -readonly [P in keyof T]: IPromiseResult>; }>((resolve, reject) => { + let values: { -readonly [P in keyof T]: IPromiseResult>; } = [] as any; + let pending = 1; // Prefix to 1 so we finish iterating over all of the input promises first + + function processItem(item: any, idx: number) { + 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 (isArray(input)) { + arrForEach(input, processItem); + } else if (isIterator(input) || isIterable(input)) { + iterForOf(input, processItem); + } + + // Now decrement the pending so that we finish correctly + pending--; + if (pending === 0) { + // All promises were either resolved or where not a promise + resolve(values); + } + } catch (e) { + reject(e); + } + }, additionalArgs); + }); +} diff --git a/lib/src/promise/debug.ts b/lib/src/promise/debug.ts index d211ec3..206ff34 100644 --- a/lib/src/promise/debug.ts +++ b/lib/src/promise/debug.ts @@ -27,7 +27,7 @@ let _theLogger: (id: string, message: string) => void = null; * @ignore Internal function enable logging the internal state of the promise during execution, this code and references are * removed from the production artifacts */ -export const _debugLog = (id: string, message: string) => { +export const _debugLog = /*#__PURE__*/(id: string, message: string) => { //#ifdef DEBUG if (_theLogger) { _theLogger(id, message); diff --git a/lib/src/promise/event.ts b/lib/src/promise/event.ts index 3a0f827..2d734f6 100644 --- a/lib/src/promise/event.ts +++ b/lib/src/promise/event.ts @@ -6,10 +6,26 @@ * Licensed under the MIT license. */ -import { dumpObj, getDocument, safeGetLazy, ILazyValue, getInst } from "@nevware21/ts-utils"; +import { dumpObj, getDocument, getInst, ICachedValue, createCachedValue, safe } from "@nevware21/ts-utils"; const DISPATCH_EVENT = "dispatchEvent"; -let _hasInitEvent: ILazyValue; +let _hasInitEvent: ICachedValue; + +/** + * @internal + * @ignore + * Helper function to determine if the document has the `initEvent` function + * @param doc - The document to check + * @returns + */ +function _hasInitEventFn(doc: Document) { + let evt: any; + if (doc && doc.createEvent) { + evt = doc.createEvent("Event"); + } + + return (!!evt && evt.initEvent); +} /** * @internal @@ -22,14 +38,7 @@ let _hasInitEvent: ILazyValue; export function emitEvent(target: any, evtName: string, populateEvent: (theEvt: Event | any) => Event | any, useNewEvent: boolean) { let doc = getDocument(); - !_hasInitEvent && (_hasInitEvent = safeGetLazy(() => { - let evt: any; - if (doc && doc.createEvent) { - evt = doc.createEvent("Event"); - } - - return (!!evt && evt.initEvent); - }, null)); + !_hasInitEvent && (_hasInitEvent = createCachedValue(!!safe(_hasInitEventFn, [ doc ]).v)); let theEvt: Event = _hasInitEvent.v ? doc.createEvent("Event") : (useNewEvent ? new Event(evtName) : {} as Event); populateEvent && populateEvent(theEvt); diff --git a/lib/src/promise/idlePromise.ts b/lib/src/promise/idlePromise.ts index fb2b8d4..f02daed 100644 --- a/lib/src/promise/idlePromise.ts +++ b/lib/src/promise/idlePromise.ts @@ -6,14 +6,17 @@ * Licensed under the MIT license. */ -import { isUndefined } from "@nevware21/ts-utils"; -import { _createAllPromise, _createPromise, _createRejectedPromise, _createResolvedPromise } from "./base"; +import { ICachedValue, isUndefined } from "@nevware21/ts-utils"; +import { _createAllPromise, _createAllSettledPromise, _createPromise, _createRejectedPromise, _createResolvedPromise } from "./base"; import { IPromise } from "../interfaces/IPromise"; import { idleItemProcessor } from "./itemProcessor"; import { PromiseExecutor } from "../interfaces/types"; +import { IPromiseResult } from "../interfaces/IPromiseResult"; let _defaultIdleTimeout: number; +let _allIdleSettledCreator: ICachedValue<(input: T, timeout?: number) => IPromise<{ -readonly [P in keyof T]: IPromiseResult>; }>>; + /** * Sets the global default idle timeout / deadline to use when no timeout is passed during promise creation. * @param idleDeadline - Specifies the time in milliseconds to use as the idle timeout / deadline by when any @@ -54,6 +57,7 @@ export function createIdlePromise(executor: PromiseExecutor, timeout?: num * the `requestIdleCallback` API (if available) with the optional provided timeout value to schedule * when the chained items will be executed. (eg. `then()`; `catch()`; `finally()`). * @group Idle + * @group Promise * @group All * @param input - The array of promises to wait to be resolved / rejected before resolving or rejecting the new promise * @param timeout @@ -65,7 +69,7 @@ export function createIdlePromise(executor: PromiseExecutor, timeout?: num * promises reject. * */ -export const createIdleAllPromise: (input: PromiseLike[], timeout?: number) => IPromise = _createAllPromise(createIdlePromise); +export const createIdleAllPromise: (input: Iterable>, timeout?: number) => IPromise = /*#__PURE__*/_createAllPromise(createIdlePromise); /** * Returns an idle Promise instance that is already resolved with the given value. If the value passed is @@ -74,11 +78,12 @@ export const createIdleAllPromise: (input: PromiseLike[], timeout?: number * `requestIdleCallback` API (if available) with the optional provided timeout value to schedule when * the chained items will be executed. (eg. `then()`; `finally()`). * @group Idle + * @group Promise * @group Resolved * @param value - The value to be used by this `Promise`. Can also be a `Promise` or a thenable to resolve. * @param timeout - Optional timeout to wait before processing the items, defaults to zero. */ -export const createIdleResolvedPromise: (value: T, timeout?: number) => IPromise = _createResolvedPromise(createIdlePromise); +export const createIdleResolvedPromise: (value: T, timeout?: number) => IPromise = /*#__PURE__*/_createResolvedPromise(createIdlePromise); /** * Returns an idle Promise instance that is already rejected with the given reason. @@ -86,8 +91,88 @@ export const createIdleResolvedPromise: (value: T, timeout?: number) => IProm * (if available) with the optional provided timeout value to schedule when the chained items will * be executed. (eg. `catch()`; `finally()`). * @group Idle + * @group Promise * @group Rejected * @param reason - The rejection reason * @param timeout - Optional timeout to wait before processing the items, defaults to zero. */ -export const createIdleRejectedPromise: (reason: any, timeout?: number) => IPromise = _createRejectedPromise(createIdlePromise); +export const createIdleRejectedPromise: (reason: any, timeout?: number) => IPromise = /*#__PURE__*/_createRejectedPromise(createIdlePromise); + +/** + * Returns a single Promise instance that resolves to an array of the results from the input promises. + * This returned promise will resolve and execute it's pending chained operations based on the + * {@link createIdlePromise idle} promise implementation. Any chained operations will execute + * __asynchronously__ when the environment is idle as the final operation pending promises have resolved, + * or if the input contains no promises. It will resolve only after all of the input promises have either + * resolved or rejected, and will resolve with an array of {@link IPromiseResult } objects that each describe + * the outcome of each promise. + * @since 0.5.0 + * @group Idle + * @group Promise + * @group AllSettled + * @param values - The iterator of promises to wait to be resolved / rejected before resolving or rejecting the new promise + * @param timeout - Optional timeout to wait before processing the items, defaults to zero, only used when Native promises are not available. + * @returns A pending `Promise` that will resolve to an array of {@link IPromiseResult } objects that each describe the outcome of each promise. + * + * @example + * ```ts + * const promises = [ + * createResolvedPromise(1), + * createResolvedPromise(2), + * createResolvedPromise(3), + * createRejectedPromise("error"), + * ]; + * + * const results = await createAllSettledPromise(promises); + * + * // results is: + * // [ + * // { status: "fulfilled", value: 1 }, + * // { status: "fulfilled", value: 2 }, + * // { status: "fulfilled", value: 3 }, + * // { status: "rejected", reason: "error" } + * // ] + * ``` + */ +export function createIdleAllSettledPromise(values: Iterable> | Iterator>, timeout?: number): IPromise>[]>; + +/** + * Returns a single Promise instance that resolves to an array of the results from the input promises. + * This returned promise will resolve and execute it's pending chained operations based on the + * {@link createIdlePromise idle} promise implementation. Any chained operations will execute + * __asynchronously__ when the environment is idle as the final operation pending promises have resolved, + * or if the input contains no promises. It will resolve only after all of the input promises have either + * resolved or rejected, and will resolve with an array of {@link IPromiseResult } objects that each describe + * the outcome of each promise. + * @since 0.5.0 + * @group Idle + * @group Promise + * @group AllSettled + * @param input - An array of promises to wait to be resolved / rejected before resolving or rejecting the new promise + * @param timeout - Optional timeout to wait before processing the items, defaults to zero, only used when Native promises are not available. + * @returns A pending `Promise` that will resolve to an array of {@link IPromiseResult } objects that each describe the outcome of each promise. + * + * @example + * ```ts + * const promises = [ + * createResolvedPromise(1), + * createResolvedPromise(2), + * createResolvedPromise(3), + * createRejectedPromise("error"), + * ]; + * + * const results = await createAllSettledPromise(promises); + * + * // results is: + * // [ + * // { status: "fulfilled", value: 1 }, + * // { status: "fulfilled", value: 2 }, + * // { status: "fulfilled", value: 3 }, + * // { status: "rejected", reason: "error" } + * // ] + * ``` + */ +export function createIdleAllSettledPromise(input: T, timeout?: number): IPromise<{ -readonly [P in keyof T]: IPromiseResult>; }> { + !_allIdleSettledCreator && (_allIdleSettledCreator = _createAllSettledPromise(createIdlePromise)); + return _allIdleSettledCreator.v(input, timeout); +} \ No newline at end of file diff --git a/lib/src/promise/itemProcessor.ts b/lib/src/promise/itemProcessor.ts index 6af9836..7b0dae6 100644 --- a/lib/src/promise/itemProcessor.ts +++ b/lib/src/promise/itemProcessor.ts @@ -14,7 +14,7 @@ export type PromisePendingProcessor = (pending: PromisePendingFn[]) => void; export type PromisePendingFn = () => void; export type PromiseCreatorFn = (newExecutor: PromiseExecutor, ...extraArgs: any) => IPromise; -const _processPendingItems = (pending: PromisePendingFn[]) => { +const _processPendingItems = /*#__PURE__*/(pending: PromisePendingFn[]) => { arrForEach(pending, (fn: PromisePendingFn) => { try { fn(); diff --git a/lib/src/promise/nativePromise.ts b/lib/src/promise/nativePromise.ts index 6e08aab..02f8bb0 100644 --- a/lib/src/promise/nativePromise.ts +++ b/lib/src/promise/nativePromise.ts @@ -7,14 +7,17 @@ */ import { createAsyncPromise } from "./asyncPromise"; -import { _createAllPromise, _createRejectedPromise, _createResolvedPromise } from "./base"; +import { _createAllPromise, _createAllSettledPromise, _createRejectedPromise, _createResolvedPromise } from "./base"; import { IPromise } from "../interfaces/IPromise"; import { ePromiseState, STRING_STATES } from "../internal/state"; import { PromiseExecutor } from "../interfaces/types"; -import { dumpObj, lazySafeGetInst, ILazyValue, isFunction, objDefineProp, throwTypeError } from "@nevware21/ts-utils"; +import { dumpObj, isFunction, objDefineProp, throwTypeError, getInst, ICachedValue, createCachedValue, safe } from "@nevware21/ts-utils"; import { STR_PROMISE } from "../internal/constants"; +import { IPromiseResult } from "../interfaces/IPromiseResult"; -let _isPromiseSupported: ILazyValue; +let _promiseCls: ICachedValue; + +let _allNativeSettledCreator: ICachedValue<(input: T, timeout?: number) => IPromise<{ -readonly [P in keyof T]: IPromiseResult>; }>>; /** * Creates a Promise instance that when resolved or rejected will execute it's pending chained operations using the @@ -30,9 +33,8 @@ let _isPromiseSupported: ILazyValue; * @param timeout - Optional timeout to wait before processing the items, defaults to zero. */ export function createNativePromise(executor: PromiseExecutor, timeout?: number): IPromise { - !_isPromiseSupported && (_isPromiseSupported = lazySafeGetInst(STR_PROMISE)); - - const PrmCls = _isPromiseSupported.v; + !_promiseCls && (_promiseCls = createCachedValue(safe(getInst, [STR_PROMISE]).v || null as any)); + const PrmCls = _promiseCls.v; if (!PrmCls) { return createAsyncPromise(executor); } @@ -77,6 +79,7 @@ export function createNativePromise(executor: PromiseExecutor, timeout?: n * and will reject with this first rejection message / error. * If the runtime doesn't support the Promise.all it will fallback back to an asynchronous Promise implementation. * @group Alias + * @group Promise * @group All * @group Native * @param input - The array of promises to wait to be resolved / rejected before resolving or rejecting the new promise @@ -89,7 +92,7 @@ export function createNativePromise(executor: PromiseExecutor, timeout?: n * promises reject. * */ -export const createNativeAllPromise: (input: PromiseLike[], timeout?: number) => IPromise = _createAllPromise(createNativePromise); +export const createNativeAllPromise: (input: Iterable>, timeout?: number) => IPromise = /*#__PURE__*/_createAllPromise(createNativePromise); /** * Returns a single asynchronous Promise instance that is already resolved with the given value. If the value passed is @@ -97,21 +100,102 @@ export const createNativeAllPromise: (input: PromiseLike[], timeout?: numb * If a new instance is returned then any chained operations will execute __asynchronously__ using the optional * timeout value to schedule when the chained items will be executed.(eg. `then()`; `finally()`). * @group Alias + * @group Promise * @group Resolved * @group Native * @param value - The value to be used by this `Promise`. Can also be a `Promise` or a thenable to resolve. * @param timeout - Optional timeout to wait before processing the items, defaults to zero. */ -export const createNativeResolvedPromise: (value: T, timeout?: number) => Promise = _createResolvedPromise(createNativePromise); +export const createNativeResolvedPromise: (value: T, timeout?: number) => Promise = /*#__PURE__*/_createResolvedPromise(createNativePromise); /** * Returns a single asynchronous Promise instance that is already rejected with the given reason. * Any chained operations will execute __asynchronously__ using the optional timeout value to schedule * when then chained items will be executed. (eg. `catch()`; `finally()`). * @group Alias + * @group Promise * @group Rejected * @group Native * @param reason - The rejection reason * @param timeout - Optional timeout to wait before processing the items, defaults to zero. */ -export const createNativeRejectedPromise: (reason: any, timeout?: number) => Promise = _createRejectedPromise(createNativePromise); +export const createNativeRejectedPromise: (reason: any, timeout?: number) => Promise = /*#__PURE__*/_createRejectedPromise(createNativePromise); + +/** + * Returns a single asynchronous Promise instance that resolves to an array of the results from the input promises. + * This returned promise will resolve and execute it's pending chained operations using {@link createNativePromise native} + * environment promise implementation, if the runtime does not provide any native then the optional provided + * timeout value will be used to schedule when the chained items will be executed or if the input contains no promises. + * It will resolve only after all of the input promises have either resolved or rejected, and will resolve with an array + * of {@link IPromiseResult } objects that each describe the outcome of each promise. + * @since 0.5.0 + * @group Alias + * @group Promise + * @group AllSettled + * @group Native + * @param values - The iterator of promises to wait to be resolved / rejected before resolving or rejecting the new promise + * @param timeout - Optional timeout to wait before processing the items, defaults to zero, only used when Native promises are not available. + * @returns A pending `Promise` that will resolve to an array of {@link IPromiseResult } objects that each describe the outcome of each promise. + * + * @example + * ```ts + * const promises = [ + * createNativeResolvedPromise(1), + * createNativeResolvedPromise(2), + * createNativeResolvedPromise(3), + * createNativeRejectedPromise("error"), + * ]; + * + * const results = await createNativeAllSettledPromise(promises); + * + * // results is: + * // [ + * // { status: "fulfilled", value: 1 }, + * // { status: "fulfilled", value: 2 }, + * // { status: "fulfilled", value: 3 }, + * // { status: "rejected", reason: "error" } + * // ] + * ``` + */ +export function createNativeAllSettledPromise(values: Iterable> | Iterator>, timeout?: number): IPromise>[]>; + +/** + * Returns a single asynchronous Promise instance that resolves to an array of the results from the input promises. + * This returned promise will resolve and execute it's pending chained operations using {@link createNativePromise native} + * environment promise implementation, if the runtime does not provide any native then the optional provided + * timeout value will be used to schedule when the chained items will be executed or if the input contains no promises. + * It will resolve only after all of the input promises have either resolved or rejected, and will resolve with an array + * of {@link IPromiseResult } objects that each describe the outcome of each promise. + * @since 0.5.0 + * @group Alias + * @group Promise + * @group AllSettled + * @group Native + * @param input - An array of promises to wait to be resolved / rejected before resolving or rejecting the new promise + * @param timeout - Optional timeout to wait before processing the items, defaults to zero, only used when Native promises are not available. + * @returns A pending `Promise` that will resolve to an array of {@link IPromiseResult } objects that each describe the outcome of each promise. + * + * @example + * ```ts + * const promises = [ + * createNativeResolvedPromise(1), + * createNativeResolvedPromise(2), + * createNativeResolvedPromise(3), + * createNativeRejectedPromise("error"), + * ]; + * + * const results = await createNativeAllSettledPromise(promises); + * + * // results is: + * // [ + * // { status: "fulfilled", value: 1 }, + * // { status: "fulfilled", value: 2 }, + * // { status: "fulfilled", value: 3 }, + * // { status: "rejected", reason: "error" } + * // ] + * ``` + */ +export function createNativeAllSettledPromise(input: T, timeout?: number): IPromise<{ -readonly [P in keyof T]: IPromiseResult>; }> { + !_allNativeSettledCreator && (_allNativeSettledCreator = _createAllSettledPromise(createNativePromise)); + return _allNativeSettledCreator.v(input, timeout); +} \ No newline at end of file diff --git a/lib/src/promise/promise.ts b/lib/src/promise/promise.ts index 767c375..ee7dabc 100644 --- a/lib/src/promise/promise.ts +++ b/lib/src/promise/promise.ts @@ -6,12 +6,16 @@ * Licensed under the MIT license. */ -import { _createAllPromise, _createRejectedPromise, _createResolvedPromise } from "./base"; +import { getLazy, ICachedValue, ILazyValue } from "@nevware21/ts-utils"; +import { _createAllPromise, _createAllSettledPromise, _createRejectedPromise, _createResolvedPromise } from "./base"; import { IPromise } from "../interfaces/IPromise"; import { createNativePromise } from "./nativePromise"; import { PromiseExecutor } from "../interfaces/types"; +import { IPromiseResult } from "../interfaces/IPromiseResult"; + +let _promiseCreator: ILazyValue<(executor: PromiseExecutor, timeout?: number) => IPromise>; +let _allSettledCreator: ICachedValue<(input: T, timeout?: number) => IPromise<{ -readonly [P in keyof T]: IPromiseResult>; }>>; -let _promiseCreator: (executor: PromiseExecutor, timeout?: number) => IPromise; /** * Set the default promise implementation to use when calling `createPromise`; `createAllPromise`; `createResolvedPromise` @@ -26,7 +30,7 @@ let _promiseCreator: (executor: PromiseExecutor, timeout?: number) => IPro export function setCreatePromiseImpl( creator: (executor: PromiseExecutor, timeout?: number) => IPromise ) { - _promiseCreator = creator || null; + _promiseCreator = creator ? getLazy(() => creator) : null; } /** @@ -39,9 +43,9 @@ export function setCreatePromiseImpl( * @param timeout - [Optional] timeout to wait before processing the items, defaults to zero. */ export function createPromise(executor: PromiseExecutor, timeout?: number): IPromise { - !_promiseCreator && (_promiseCreator = createNativePromise); + !_promiseCreator && (_promiseCreator = getLazy(() => createNativePromise)); - return _promiseCreator.call(this, executor, timeout); + return _promiseCreator.v.call(this, executor, timeout); } /** @@ -52,6 +56,7 @@ export function createPromise(executor: PromiseExecutor, timeout?: number) * and will reject with this first rejection message / error. * If the runtime doesn't support the Promise.all it will fallback back to an asynchronous Promise implementation. * @group Alias + * @group Promise * @group All * @param input - The array of promises to wait to be resolved / rejected before resolving or rejecting the new promise * @param timeout @@ -63,7 +68,7 @@ export function createPromise(executor: PromiseExecutor, timeout?: number) * promises reject. * */ -export const createAllPromise: (input: PromiseLike[], timeout?: number) => IPromise = _createAllPromise(createPromise); +export const createAllPromise: (input: Iterable>, timeout?: number) => IPromise = /*#__PURE__*/_createAllPromise(createPromise); /** * Returns a single asynchronous Promise instance that is already resolved with the given value. If the value passed is @@ -71,19 +76,104 @@ export const createAllPromise: (input: PromiseLike[], timeout?: number) => * If a new instance is returned then any chained operations will execute __asynchronously__ using the optional * timeout value to schedule when the chained items will be executed.(eg. `then()`; `finally()`). * @group Alias + * @group Promise * @group Resolved * @param value - The value to be used by this `Promise`. Can also be a `Promise` or a thenable to resolve. * @param timeout - Optional timeout to wait before processing the items, defaults to zero. */ -export const createResolvedPromise: (value: T, timeout?: number) => IPromise = _createResolvedPromise(createPromise); +export const createResolvedPromise: (value: T, timeout?: number) => IPromise = /*#__PURE__*/_createResolvedPromise(createPromise); /** * Returns a single asynchronous Promise instance that is already rejected with the given reason. * Any chained operations will execute __asynchronously__ using the optional timeout value to schedule * when then chained items will be executed. (eg. `catch()`; `finally()`). * @group Alias + * @group Promise * @group Rejected * @param reason - The rejection reason * @param timeout - Optional timeout to wait before processing the items, defaults to zero. */ -export const createRejectedPromise: (reason: any, timeout?: number) => IPromise = _createRejectedPromise(createPromise); +export const createRejectedPromise: (reason: any, timeout?: number) => IPromise = /*#__PURE__*/_createRejectedPromise(createPromise); + +/** + * Returns a single Promise instance that resolves to an array of the results from the input promises. + * This returned promise will resolve and execute it's pending chained operations based on the current + * promise implementation. If the current implementation is synchronous then the chained operations will + * execute __synchronously__ in the same execution cycle as the final operation pending promises have resolved, + * or if the input contains no promises. If the current implementation is asynchronous then the chained + * operations will execute __asynchronously__ using the optional provided timeout value to schedule when the + * chained items will be executed or if the input contains no promises. + * It will resolve only after all of the input promises have either resolved or rejected, and will resolve with an array + * of {@link IPromiseResult } objects that each describe the outcome of each promise. + * @since 0.5.0 + * @group Alias + * @group Promise + * @group AllSettled + * @param values - The iterator of promises to wait to be resolved / rejected before resolving or rejecting the new promise + * @param timeout - Optional timeout to wait before processing the items, defaults to zero, only used when Native promises are not available. + * @returns A pending `Promise` that will resolve to an array of {@link IPromiseResult } objects that each describe the outcome of each promise. + * + * @example + * ```ts + * const promises = [ + * createResolvedPromise(1), + * createResolvedPromise(2), + * createResolvedPromise(3), + * createRejectedPromise("error"), + * ]; + * + * const results = await createAllSettledPromise(promises); + * + * // results is: + * // [ + * // { status: "fulfilled", value: 1 }, + * // { status: "fulfilled", value: 2 }, + * // { status: "fulfilled", value: 3 }, + * // { status: "rejected", reason: "error" } + * // ] + * ``` + */ +export function createAllSettledPromise(values: Iterable> | Iterator>, timeout?: number): IPromise>[]>; + +/** + * Returns a single Promise instance that resolves to an array of the results from the input promises. + * This returned promise will resolve and execute it's pending chained operations based on the current + * promise implementation. If the current implementation is synchronous then the chained operations will + * execute __synchronously__ in the same execution cycle as the final operation pending promises have resolved, + * or if the input contains no promises. If the current implementation is asynchronous then the chained + * operations will execute __asynchronously__ using the optional provided timeout value to schedule when the + * chained items will be executed or if the input contains no promises. + * It will resolve only after all of the input promises have either resolved or rejected, and will resolve with an array + * of {@link IPromiseResult } objects that each describe the outcome of each promise. + * @since 0.5.0 + * @group Alias + * @group Promise + * @group AllSettled + * @param input - An array of promises to wait to be resolved / rejected before resolving or rejecting the new promise + * @param timeout - Optional timeout to wait before processing the items, defaults to zero, only used when Native promises are not available. + * @returns A pending `Promise` that will resolve to an array of {@link IPromiseResult } objects that each describe the outcome of each promise. + * + * @example + * ```ts + * const promises = [ + * createResolvedPromise(1), + * createResolvedPromise(2), + * createResolvedPromise(3), + * createRejectedPromise("error"), + * ]; + * + * const results = await createAllSettledPromise(promises); + * + * // results is: + * // [ + * // { status: "fulfilled", value: 1 }, + * // { status: "fulfilled", value: 2 }, + * // { status: "fulfilled", value: 3 }, + * // { status: "rejected", reason: "error" } + * // ] + * ``` + */ +export function createAllSettledPromise(input: T, timeout?: number): IPromise<{ -readonly [P in keyof T]: IPromiseResult>; }> { + !_allSettledCreator && (_allSettledCreator = _createAllSettledPromise(createPromise)); + return _allSettledCreator.v(input, timeout); +} \ No newline at end of file diff --git a/lib/src/promise/syncPromise.ts b/lib/src/promise/syncPromise.ts index 2c97de1..5791fa6 100644 --- a/lib/src/promise/syncPromise.ts +++ b/lib/src/promise/syncPromise.ts @@ -6,10 +6,14 @@ * Licensed under the MIT license. */ -import { _createAllPromise, _createPromise, _createRejectedPromise, _createResolvedPromise } from "./base"; +import { _createAllPromise, _createAllSettledPromise, _createPromise, _createRejectedPromise, _createResolvedPromise } from "./base"; import { IPromise } from "../interfaces/IPromise"; import { syncItemProcessor } from "./itemProcessor"; import { PromiseExecutor } from "../interfaces/types"; +import { IPromiseResult } from "../interfaces/IPromiseResult"; +import { ICachedValue } from "@nevware21/ts-utils"; + +let _allSyncSettledCreator: ICachedValue<(input: T, timeout?: number) => IPromise<{ -readonly [P in keyof T]: IPromiseResult>; }>>; /** * Creates a synchronous Promise instance that when resolved or rejected will execute it's pending chained operations @@ -33,6 +37,7 @@ export function createSyncPromise(executor: PromiseExecutor): IPromise * When resolved or rejected any additional chained operations will execute __synchronously__ at the point of * being added (eg. `then()`; `catch()`; `finally()`). * @group Synchronous + * @group Promise * @group All * @param input - The array of promises to wait to be resolved / rejected before resolving or rejecting the new promise * @returns @@ -43,7 +48,7 @@ export function createSyncPromise(executor: PromiseExecutor): IPromise * promises reject. * */ -export const createSyncAllPromise: (input: PromiseLike[]) => IPromise = _createAllPromise(createSyncPromise); +export const createSyncAllPromise: (input: Iterable>) => IPromise = /*#__PURE__*/_createAllPromise(createSyncPromise); /** * Returns a single synchronous Promise instance that is already resolved with the given value. If the value passed is @@ -51,16 +56,97 @@ export const createSyncAllPromise: (input: PromiseLike[]) => IPromise * If a new instance is returned then any chained operations will execute __synchronously__ at the point of being * added (calling `then()`). * @group Synchronous + * @group Promise * @group Resolved * @param value - The value to be used by this `Promise`. Can also be a `Promise` or a thenable to resolve. */ -export const createSyncResolvedPromise: (value: T) => IPromise = _createResolvedPromise(createSyncPromise); +export const createSyncResolvedPromise: (value: T) => IPromise = /*#__PURE__*/_createResolvedPromise(createSyncPromise); /** * Returns a single synchronous Promise instance that is already rejected with the given reason. * Any chained operations will execute __synchronously__ at the point of being added (eg. `catch()`; `finally()`). * @group Synchronous + * @group Promise * @group Rejected * @param reason - The rejection reason */ -export const createSyncRejectedPromise: (reason: any) => IPromise = _createRejectedPromise(createSyncPromise); +export const createSyncRejectedPromise: (reason: any) => IPromise = /*#__PURE__*/_createRejectedPromise(createSyncPromise); + +/** + * Returns a single Promise instance that resolves to an array of the results from the input promises. + * This returned promise will resolve and execute it's pending chained operations based on the + * {@link createSyncPromise synchronous} promise implementation. Any chained operations will execute + * __synchronously__ in the same execution cycle as the final operation pending promises have resolved, + * or if the input contains no promises. It will resolve only after all of the input promises have either + * resolved or rejected, and will resolve with an array of {@link IPromiseResult } objects that each describe + * the outcome of each promise. + * @since 0.5.0 + * @group Synchronous + * @group Promise + * @group AllSettled + * @param values - The iterator of promises to wait to be resolved / rejected before resolving or rejecting the new promise + * @param timeout - Optional timeout to wait before processing the items, defaults to zero, only used when Native promises are not available. + * @returns A pending `Promise` that will resolve to an array of {@link IPromiseResult } objects that each describe the outcome of each promise. + * + * @example + * ```ts + * const promises = [ + * createResolvedPromise(1), + * createResolvedPromise(2), + * createResolvedPromise(3), + * createRejectedPromise("error"), + * ]; + * + * const results = await createAllSettledPromise(promises); + * + * // results is: + * // [ + * // { status: "fulfilled", value: 1 }, + * // { status: "fulfilled", value: 2 }, + * // { status: "fulfilled", value: 3 }, + * // { status: "rejected", reason: "error" } + * // ] + * ``` + */ +export function createSyncAllSettledPromise(values: Iterable> | Iterator>, timeout?: number): IPromise>[]>; + +/** + * Returns a single Promise instance that resolves to an array of the results from the input promises. + * This returned promise will resolve and execute it's pending chained operations based on the + * {@link createSyncPromise synchronous} promise implementation. Any chained operations will execute + * __synchronously__ in the same execution cycle as the final operation pending promises have resolved, + * or if the input contains no promises. It will resolve only after all of the input promises have either + * resolved or rejected, and will resolve with an array of {@link IPromiseResult } objects that each describe + * the outcome of each promise. + * @since 0.5.0 + * @group Synchronous + * @group Promise + * @group AllSettled + * @param input - An array of promises to wait to be resolved / rejected before resolving or rejecting the new promise + * @param timeout - Optional timeout to wait before processing the items, defaults to zero, only used when Native promises are not available. + * @returns A pending `Promise` that will resolve to an array of {@link IPromiseResult } objects that each describe the outcome of each promise. + * + * @example + * ```ts + * const promises = [ + * createResolvedPromise(1), + * createResolvedPromise(2), + * createResolvedPromise(3), + * createRejectedPromise("error"), + * ]; + * + * const results = await createAllSettledPromise(promises); + * + * // results is: + * // [ + * // { status: "fulfilled", value: 1 }, + * // { status: "fulfilled", value: 2 }, + * // { status: "fulfilled", value: 3 }, + * // { status: "rejected", reason: "error" } + * // ] + * ``` + */ +export function createSyncAllSettledPromise(input: T, timeout?: number): IPromise<{ -readonly [P in keyof T]: IPromiseResult>; }> { + !_allSyncSettledCreator && (_allSyncSettledCreator = _createAllSettledPromise(createSyncPromise)); + return _allSyncSettledCreator.v(input, timeout); +} \ No newline at end of file diff --git a/lib/src/promise/timeoutPromise.ts b/lib/src/promise/timeoutPromise.ts index 907894c..f3b243a 100644 --- a/lib/src/promise/timeoutPromise.ts +++ b/lib/src/promise/timeoutPromise.ts @@ -65,10 +65,10 @@ import { createPromise } from "./promise"; * }); * ``` */ -export const createTimeoutPromise = (timeout: number, resolveReject?: boolean, message?: T): IPromise => { +export function createTimeoutPromise(timeout: number, resolveReject?: boolean, message?: T): IPromise { return createPromise((resolve, reject) => { scheduleTimeout(() => { (resolveReject ? resolve : reject)(!isUndefined(message) ? message : "Timeout of " + timeout + "ms exceeded" as T); }, timeout); }); -}; +} diff --git a/lib/src/scheduler/taskScheduler.ts b/lib/src/scheduler/taskScheduler.ts index c541c72..065b9d3 100644 --- a/lib/src/scheduler/taskScheduler.ts +++ b/lib/src/scheduler/taskScheduler.ts @@ -47,11 +47,11 @@ interface _InternalDebugState { * @ignore * Empty reject function to avoid trying to re-reject */ -const _rejectDone = () => { +function _rejectDone() { // A Do nothing function } -var _createError = (type: string, evt: ITaskDetail, message?: string): Error => { +function _createError(type: string, evt: ITaskDetail, message?: string): Error { // Lazily create the class !_customErrors[type] && (_customErrors[type] = createCustomError(type)); diff --git a/lib/test/src/promise/await.test.ts b/lib/test/src/promise/await.test.ts index 258ecfd..d3371d3 100644 --- a/lib/test/src/promise/await.test.ts +++ b/lib/test/src/promise/await.test.ts @@ -297,6 +297,7 @@ describe("Validate doAwaitResponse", () => { expect(mockCallback.calledOnce).to.be.true; expect(mockCallback.firstCall.args[0]).to.deep.equal({ + status: "fulfilled", value: "resolved", rejected: false }); @@ -314,6 +315,7 @@ describe("Validate doAwaitResponse", () => { expect(mockCallback.calledOnce).to.be.true; expect(mockCallback.firstCall.args[0]).to.deep.equal({ + status: "rejected", rejected: true, reason: "rejected" }); @@ -327,6 +329,7 @@ describe("Validate doAwaitResponse", () => { expect(mockCallback.calledOnce).to.be.true; expect(mockCallback.firstCall.args[0]).to.deep.equal({ + status: "fulfilled", value: "resolved", rejected: false }); @@ -341,6 +344,7 @@ describe("Validate doAwaitResponse", () => { expect(mockCallback.calledOnce).to.be.true; expect(mockCallback.firstCall.args[0]).to.deep.equal({ + status: "fulfilled", value: "resolved", rejected: false }); @@ -361,6 +365,7 @@ describe("Validate doAwaitResponse", () => { expect(mockCallback.calledOnce).to.be.true; expect(mockCallback.firstCall.args[0]).to.deep.equal({ + status: "fulfilled", value: "resolved", rejected: false }); @@ -380,6 +385,7 @@ describe("Validate doAwaitResponse", () => { expect(mockCallback.calledOnce).to.be.true; expect(mockCallback.firstCall.args[0]).to.deep.equal({ + status: "fulfilled", value: "resolved", rejected: false }); diff --git a/lib/test/src/promise/use.await.test.ts b/lib/test/src/promise/use.await.test.ts index 4bde407..ab52b7b 100644 --- a/lib/test/src/promise/use.await.test.ts +++ b/lib/test/src/promise/use.await.test.ts @@ -7,16 +7,19 @@ */ import { assert } from "chai"; -import { getGlobal, objHasOwn, isWebWorker, isNode, scheduleTimeout, dumpObj, arrForEach, objForEachKey, setBypassLazyCache } from "@nevware21/ts-utils"; +import { getGlobal, objHasOwn, isWebWorker, isNode, scheduleTimeout, dumpObj, arrForEach, objForEachKey, setBypassLazyCache, CreateIteratorContext } from "@nevware21/ts-utils"; import { PolyPromise } from "../../../src/polyfills/promise"; -import { createAsyncPromise, createAsyncRejectedPromise } from "../../../src/promise/asyncPromise"; +import { createAsyncAllSettledPromise, createAsyncPromise, createAsyncRejectedPromise, createAsyncResolvedPromise } from "../../../src/promise/asyncPromise"; import { setPromiseDebugState } from "../../../src/promise/debug"; -import { createIdlePromise, createIdleRejectedPromise } from "../../../src/promise/idlePromise"; +import { createIdleAllSettledPromise, createIdlePromise, createIdleRejectedPromise, createIdleResolvedPromise } from "../../../src/promise/idlePromise"; import { IPromise } from "../../../src/interfaces/IPromise"; -import { createNativePromise, createNativeRejectedPromise } from "../../../src/promise/nativePromise"; -import { createSyncPromise, createSyncRejectedPromise } from "../../../src/promise/syncPromise"; +import { createNativeAllSettledPromise, createNativePromise, createNativeRejectedPromise, createNativeResolvedPromise } from "../../../src/promise/nativePromise"; +import { createSyncAllSettledPromise, createSyncPromise, createSyncRejectedPromise, createSyncResolvedPromise } from "../../../src/promise/syncPromise"; import { PromiseExecutor } from "../../../src/interfaces/types"; -import { createAllPromise, createPromise, createResolvedPromise, setCreatePromiseImpl } from "../../../src/promise/promise"; +import { createAllPromise, createPromise, setCreatePromiseImpl, createAllSettledPromise } from "../../../src/promise/promise"; +import { createIterator } from "@nevware21/ts-utils"; +import { createIterable } from "@nevware21/ts-utils"; +import { IPromiseResult } from "../../../src/interfaces/IPromiseResult"; function _expectException(cb: () => void, message: string) { try { @@ -60,7 +63,9 @@ function _unhandledNodeRejection(reason: any, promise: any) { interface TestDefinition { creator: (executor: PromiseExecutor) => IPromise; + resolved: (value: T) => IPromise; rejected: (reason: any) => IPromise; + creatorAllSettled: (values: Iterable> | Iterator>, timeout?: number) => IPromise>[]>; checkState: boolean; checkChainedState: boolean; } @@ -72,7 +77,9 @@ let testImplementations: TestImplementations = { creator: (executor: PromiseExecutor) => { return new Promise(executor); }, + resolved: Promise.resolve.bind(Promise), rejected: Promise.reject.bind(Promise), + creatorAllSettled: Promise.allSettled.bind(Promise), checkState: false, checkChainedState: false }, @@ -80,7 +87,9 @@ let testImplementations: TestImplementations = { creator: (executor: PromiseExecutor) => { return createNativePromise(executor); }, + resolved: createNativeResolvedPromise, rejected: createNativeRejectedPromise, + creatorAllSettled: createNativeAllSettledPromise, checkState: true, checkChainedState: false }, @@ -88,7 +97,9 @@ let testImplementations: TestImplementations = { creator: (executor: PromiseExecutor) => { return createAsyncPromise(executor, 1); }, + resolved: createAsyncResolvedPromise, rejected: createAsyncRejectedPromise, + creatorAllSettled: createAsyncAllSettledPromise, checkState: true, checkChainedState: true }, @@ -96,7 +107,9 @@ let testImplementations: TestImplementations = { creator: (executor: PromiseExecutor) => { return createIdlePromise(executor, 1); }, + resolved: createIdleResolvedPromise, rejected: createIdleRejectedPromise, + creatorAllSettled: createIdleAllSettledPromise, checkState: true, checkChainedState: true }, @@ -104,7 +117,9 @@ let testImplementations: TestImplementations = { creator: (executor: PromiseExecutor) => { return createIdlePromise(executor); }, + resolved: createIdleResolvedPromise, rejected: createIdleRejectedPromise, + creatorAllSettled: createAllSettledPromise, checkState: true, checkChainedState: true }, @@ -112,7 +127,9 @@ let testImplementations: TestImplementations = { creator: (executor: PromiseExecutor) => { return createSyncPromise(executor); }, + resolved: createSyncResolvedPromise, rejected: createSyncRejectedPromise, + creatorAllSettled: createSyncAllSettledPromise, checkState: true, checkChainedState: true }, @@ -120,7 +137,9 @@ let testImplementations: TestImplementations = { creator: (executor: PromiseExecutor) => { return new PolyPromise(executor); }, + resolved: PolyPromise.resolve, rejected: PolyPromise.reject, + creatorAllSettled: PolyPromise.allSettled, checkState: true, checkChainedState: true } @@ -149,12 +168,16 @@ function batchTests(testKey: string, definition: TestDefinition) { let createNewPromise = definition.creator; let createRejectedPromise = definition.rejected; + let createAllSettledPromise = definition.creatorAllSettled; + let createResolvedPromise = definition.resolved; let checkState = definition.checkState; let checkChainedState = definition.checkChainedState; beforeEach(() => { createNewPromise = definition.creator; createRejectedPromise = definition.rejected; + createAllSettledPromise = definition.creatorAllSettled; + createResolvedPromise = definition.resolved; checkState = definition.checkState; checkChainedState = definition.checkChainedState; @@ -1341,192 +1364,399 @@ function batchTests(testKey: string, definition: TestDefinition) { assert.equal(result, 21); }); - it("check create all with nothing", async () => { - let promise = createAllPromise([]); - - let values = await promise; - assert.ok(values, "A values object should have been returned"); - assert.equal(values.length, 0, "No elements should have been returned"); - - let values2 = await promise; - assert.ok(values, "A values object should have been returned"); - assert.equal(values.length, 0, "No elements should have been returned"); - - assert.ok(values === values2); - }); - - it("check create all with values resolved in the reverse order", async () => { - let promise = createAllPromise([ - createNewPromise((resolve, reject) => { - scheduleTimeout(() => { - resolve(21); - }, 5) - }), - createNewPromise((resolve, reject) => { - scheduleTimeout(() => { - resolve(42); - }, 0) - }) - ]); - - let values = await promise; - assert.ok(values, "A values object should have been returned"); - assert.equal(values.length, 2, "Two elements should have been returned"); - assert.equal(values[0], 21); - assert.equal(values[1], 42); - - let values2 = await promise; - assert.ok(values2, "A values object should have been returned"); - assert.equal(values2.length, 2, "Two elements should have been returned"); - - assert.ok(values === values2); + describe("createAllPromise", () => { + it("check create all with nothing", async () => { + let promise = createAllPromise([]); + + let values = await promise; + assert.ok(values, "A values object should have been returned"); + assert.equal(values.length, 0, "No elements should have been returned"); + + let values2 = await promise; + assert.ok(values, "A values object should have been returned"); + assert.equal(values.length, 0, "No elements should have been returned"); + + assert.ok(values === values2); + }); + + it("check create all with values resolved in the reverse order", async () => { + let promise = createAllPromise([ + createNewPromise((resolve, reject) => { + scheduleTimeout(() => { + resolve(21); + }, 5) + }), + createNewPromise((resolve, reject) => { + scheduleTimeout(() => { + resolve(42); + }, 0) + }) + ]); + + let values = await promise; + assert.ok(values, "A values object should have been returned"); + assert.equal(values.length, 2, "Two elements should have been returned"); + assert.equal(values[0], 21); + assert.equal(values[1], 42); + + let values2 = await promise; + assert.ok(values2, "A values object should have been returned"); + assert.equal(values2.length, 2, "Two elements should have been returned"); + + assert.ok(values === values2); + }); + + it("check create all with values resolved in the order", async () => { + let promise = createAllPromise([ + createNewPromise((resolve, reject) => { + scheduleTimeout(() => { + resolve(21); + }, 0) + }), + createNewPromise((resolve, reject) => { + scheduleTimeout(() => { + resolve(42); + }, 5) + }) + ]); + + let values = await promise; + assert.ok(values, "A values object should have been returned"); + assert.equal(values.length, 2, "Two elements should have been returned"); + assert.equal(values[0], 21); + assert.equal(values[1], 42); + + let values2 = await promise; + assert.ok(values2, "A values object should have been returned"); + assert.equal(values2.length, 2, "Two elements should have been returned"); + + assert.ok(values === values2); + }); + + it("check create all with values resolved in the order with a rejected promise", async () => { + let promise = createAllPromise([ + createNewPromise((resolve, reject) => { + scheduleTimeout(() => { + resolve(21); + }, 0) + }), + createNewPromise((resolve, reject) => { + scheduleTimeout(() => { + reject(new Error("Simulated failure")); + }, 5) + }) + ]); + + try { + await promise; + } catch (e) { + assert.ok(true, "Caught: " + dumpObj(e)); + assert.equal(e.message, "Simulated failure"); + } + + try { + await promise; + } catch (e) { + assert.ok(true, "Caught: " + dumpObj(e)); + assert.equal(e.message, "Simulated failure"); + } + }); + + it("check create all with values resolved in the order with a rejected promise and a finally", async () => { + let promise = createAllPromise([ + createNewPromise((resolve, reject) => { + scheduleTimeout(() => { + resolve(21); + }, 0) + }), + createNewPromise((resolve, reject) => { + scheduleTimeout(() => { + reject(new Error("Simulated failure")); + }, 5) + }) + ]).finally(() => { + //console.log("Finally called"); + }); + + try { + await promise; + } catch (e) { + assert.ok(true, "Caught: " + dumpObj(e)); + assert.equal(e.message, "Simulated failure"); + } + + try { + await promise; + } catch (e) { + assert.ok(true, "Caught: " + dumpObj(e)); + assert.equal(e.message, "Simulated failure"); + } + }); + + it("check create all with values resolved in the order with a rejected promise and a finally and a catch", async () => { + let catchCalled = false; + let finallyCalled = false; + let promise = createAllPromise([ + createNewPromise((resolve, reject) => { + scheduleTimeout(() => { + resolve(21); + }, 0) + }), + createNewPromise((resolve, reject) => { + scheduleTimeout(() => { + reject(new Error("Simulated failure")); + }, 5) + }) + ]).finally(() => { + finallyCalled = true; + }).catch((e) => { + catchCalled = true; + }); + + try { + await promise; + } catch (e) { + assert.ok(true, "Caught: " + dumpObj(e)); + assert.equal(e.message, "Simulated failure"); + } + + assert.equal(catchCalled, true, "Catch was called"); + assert.equal(finallyCalled, true, "Finally was called"); + + try { + await promise; + } catch (e) { + assert.ok(true, "Caught: " + dumpObj(e)); + assert.equal(e.message, "Simulated failure"); + } + }); + + it("check create all where a resolve function throws", async () => { + let promise = createAllPromise([ + createRejectedPromise("Rejected"), + createResolvedPromise(42) + ]).finally(() => { + //console.log("Finally called"); + }); + + try { + await promise; + } catch (e) { + assert.ok(true, "Caught: " + dumpObj(e)); + assert.equal(e, "Rejected"); + } + + try { + await promise; + } catch (e) { + assert.ok(true, "Caught: " + dumpObj(e)); + assert.equal(e, "Rejected"); + } + }); }); + + describe("createAllSettledPromise with Array", () => { + it("check create all settled with nothing", async () => { + let promise = createAllSettledPromise([]); + + let values = await promise; + assert.ok(values, "A values object should have been returned"); + assert.equal(values.length, 0, "No elements should have been returned"); + + let values2 = await promise; + assert.ok(values, "A values object should have been returned"); + assert.equal(values.length, 0, "No elements should have been returned"); + + assert.ok(values === values2); + }); - it("check create all with values resolved in the order", async () => { - let promise = createAllPromise([ - createNewPromise((resolve, reject) => { - scheduleTimeout(() => { - resolve(21); - }, 0) - }), - createNewPromise((resolve, reject) => { - scheduleTimeout(() => { - resolve(42); - }, 5) - }) - ]); - - let values = await promise; - assert.ok(values, "A values object should have been returned"); - assert.equal(values.length, 2, "Two elements should have been returned"); - assert.equal(values[0], 21); - assert.equal(values[1], 42); - - let values2 = await promise; - assert.ok(values2, "A values object should have been returned"); - assert.equal(values2.length, 2, "Two elements should have been returned"); - - assert.ok(values === values2); + it("check create all settled with values resolved in the reverse order", async () => { + let promise = createAllSettledPromise([ + createNewPromise((resolve, reject) => { + scheduleTimeout(() => { + resolve(21); + }, 5) + }), + createNewPromise((resolve, reject) => { + scheduleTimeout(() => { + resolve(42); + }, 0) + }) + ]); + + let values = await promise; + assert.ok(values, "A values object should have been returned"); + assert.equal(values.length, 2, "Two elements should have been returned"); + assert.equal(values[0].status, "fulfilled"); + assert.equal(values[0].value, 21); + assert.equal(values[1].status, "fulfilled"); + assert.equal(values[1].value, 42); + + let values2 = await promise; + assert.ok(values2, "A values object should have been returned"); + assert.equal(values2.length, 2, "Two elements should have been returned"); + + assert.ok(values === values2); + + Promise.allSettled([ + createNewPromise((resolve, reject) => { + scheduleTimeout(() => { + resolve(21); + }, 5) + }), + createNewPromise((resolve, reject) => { + scheduleTimeout(() => { + resolve(42); + }, 0) + }) + ]); + }); }); - it("check create all with values resolved in the order with a rejected promise", async () => { - let promise = createAllPromise([ - createNewPromise((resolve, reject) => { - scheduleTimeout(() => { - resolve(21); - }, 0) - }), - createNewPromise((resolve, reject) => { - scheduleTimeout(() => { - reject(new Error("Simulated failure")); - }, 5) - }) - ]); - - try { - await promise; - } catch (e) { - assert.ok(true, "Caught: " + dumpObj(e)); - assert.equal(e.message, "Simulated failure"); - } - - try { - await promise; - } catch (e) { - assert.ok(true, "Caught: " + dumpObj(e)); - assert.equal(e.message, "Simulated failure"); - } - }); + if (testKey !== "system") { + describe("createAllSettledPromise with Iterator", () => { + it("check create all settled with nothing", async () => { + let theValues: any[] = [ ]; + let idx = -1 + + function getNextFn() { + idx++; + let isDone = idx >= theValues.length; + if (!isDone) { + // this is passed as the current iterator + // so you can directly assign the next "value" that will be returned + this.v = theValues[idx]; + } + + return isDone; + } + + let theIterator = createIterator({ n: getNextFn }); + let promise = createAllSettledPromise(theIterator); + + let values = await promise; + assert.ok(values, "A values object should have been returned"); + assert.equal(values.length, 0, "No elements should have been returned"); + + let values2 = await promise; + assert.ok(values, "A values object should have been returned"); + assert.equal(values.length, 0, "No elements should have been returned"); + + assert.ok(values === values2); + }); - it("check create all with values resolved in the order with a rejected promise and a finally", async () => { - let promise = createAllPromise([ - createNewPromise((resolve, reject) => { - scheduleTimeout(() => { - resolve(21); - }, 0) - }), - createNewPromise((resolve, reject) => { - scheduleTimeout(() => { - reject(new Error("Simulated failure")); - }, 5) - }) - ]).finally(() => { - //console.log("Finally called"); + it("check create all settled with some values", async () => { + let theValues = [ 1, 2, 3, 5, 8, 13, 21, 34, 55, 89 ]; + let idx = -1 + + function getNextFn() { + idx++; + let isDone = idx >= theValues.length; + if (!isDone) { + // this is passed as the current iterator + // so you can directly assign the next "value" that will be returned + this.v = theValues[idx]; + } + + return isDone; + } + + let theIterator = createIterator({ n: getNextFn }); + let promise = createAllSettledPromise(theIterator); + + let values = await promise; + assert.ok(values, "A values object should have been returned"); + assert.equal(values.length, 10, "No elements should have been returned"); + + let values2 = await promise; + assert.ok(values, "A values object should have been returned"); + assert.equal(values.length, 10, "No elements should have been returned"); + + assert.ok(values === values2); + }); }); + } - try { - await promise; - } catch (e) { - assert.ok(true, "Caught: " + dumpObj(e)); - assert.equal(e.message, "Simulated failure"); - } - - try { - await promise; - } catch (e) { - assert.ok(true, "Caught: " + dumpObj(e)); - assert.equal(e.message, "Simulated failure"); - } - }); - - it("check create all with values resolved in the order with a rejected promise and a finally and a catch", async () => { - let catchCalled = false; - let finallyCalled = false; - let promise = createAllPromise([ - createNewPromise((resolve, reject) => { - scheduleTimeout(() => { - resolve(21); - }, 0) - }), - createNewPromise((resolve, reject) => { - scheduleTimeout(() => { - reject(new Error("Simulated failure")); - }, 5) - }) - ]).finally(() => { - finallyCalled = true; - }).catch((e) => { - catchCalled = true; + describe("createAllSettledPromise with Iterable", () => { + it("check create all settled with nothing", async () => { + let fibCtx: CreateIteratorContext = { + n: function() { + // Return done + return true; + } + }; + + let theIterator = createIterable(fibCtx); + let promise = createAllSettledPromise(theIterator); + + let values = await promise; + assert.ok(values, "A values object should have been returned"); + assert.equal(values.length, 0, "No elements should have been returned"); + + let values2 = await promise; + assert.ok(values, "A values object should have been returned"); + assert.equal(values.length, 0, "No elements should have been returned"); + + assert.ok(values === values2); }); - try { - await promise; - } catch (e) { - assert.ok(true, "Caught: " + dumpObj(e)); - assert.equal(e.message, "Simulated failure"); - } - - assert.equal(catchCalled, true, "Catch was called"); - assert.equal(finallyCalled, true, "Finally was called"); - - try { - await promise; - } catch (e) { - assert.ok(true, "Caught: " + dumpObj(e)); - assert.equal(e.message, "Simulated failure"); - } + it("check create all settled with some values", async () => { + let current = 0; + let next = 1; + let fibCtx: CreateIteratorContext = { + n: function() { + fibCtx.v = current; + current = next; + next = fibCtx.v + next; + + // Stop once the value is > 32 + return next > 32; + }, + r: function(value) { + return value; + } + }; + + let theIterator = createIterable(fibCtx); + let promise = createAllSettledPromise(theIterator); + + let values = await promise; + assert.ok(values, "A values object should have been returned"); + assert.equal(values.length, 7, "No elements should have been returned"); + assert.deepEqual(values.map((v) => v.status), [ "fulfilled", "fulfilled", "fulfilled", "fulfilled", "fulfilled", "fulfilled", "fulfilled" ]); + assert.deepEqual(values.map((v) => v.value), [ 0, 1, 1, 2, 3, 5, 8 ]); + + let values2 = await promise; + assert.ok(values, "A values object should have been returned"); + assert.equal(values.length, 7, "No elements should have been returned"); + assert.deepEqual(values.map((v) => v.status), [ "fulfilled", "fulfilled", "fulfilled", "fulfilled", "fulfilled", "fulfilled", "fulfilled" ]); + assert.deepEqual(values.map((v) => v.value), [ 0, 1, 1, 2, 3, 5, 8 ]); + + assert.ok(values === values2); + assert.equal(values, values2); + }); }); - it("check create all where a resolve function throws", async () => { - let promise = createAllPromise([ - createRejectedPromise("Rejected"), - createResolvedPromise(42) - ]).finally(() => { - //console.log("Finally called"); + describe("createAllSettledPromise with rejected", () => { + it("should handle a mixture of fulfilled and rejected promise values", async () => { + const promises = [ + createResolvedPromise("resolved1"), + createRejectedPromise("rejected1"), + createResolvedPromise("resolved2"), + createRejectedPromise("rejected2") + ]; + + const theIterator = promises[Symbol.iterator](); + const promise = createAllSettledPromise(theIterator); + + const values = await promise; + + assert.deepEqual(values, [ + { status: "fulfilled", value: "resolved1" }, + { status: "rejected", reason: "rejected1" }, + { status: "fulfilled", value: "resolved2" }, + { status: "rejected", reason: "rejected2" } + ]); }); - - try { - await promise; - } catch (e) { - assert.ok(true, "Caught: " + dumpObj(e)); - assert.equal(e, "Rejected"); - } - - try { - await promise; - } catch (e) { - assert.ok(true, "Caught: " + dumpObj(e)); - assert.equal(e, "Rejected"); - } }); } diff --git a/lib/test/src/promise/use.doAwait.test.ts b/lib/test/src/promise/use.doAwait.test.ts index 61cbfa5..84f89c0 100644 --- a/lib/test/src/promise/use.doAwait.test.ts +++ b/lib/test/src/promise/use.doAwait.test.ts @@ -7,7 +7,7 @@ */ import { assert } from "chai"; -import { arrForEach, dumpObj, getGlobal, isNode, isWebWorker, objForEachKey, objHasOwn, scheduleTimeout, setBypassLazyCache } from "@nevware21/ts-utils"; +import { arrForEach, dumpObj, getGlobal, isNode, isWebWorker, objForEachKey, objHasOwn, scheduleTimeout, setBypassLazyCache, setDefaultIdleTimeout } from "@nevware21/ts-utils"; import { createAsyncAllPromise, createAsyncPromise, createAsyncRejectedPromise } from "../../../src/promise/asyncPromise"; import { doAwait, doAwaitResponse } from "../../../src/promise/await"; import { setPromiseDebugState } from "../../../src/promise/debug"; @@ -165,7 +165,8 @@ function batchTests(testKey: string, definition: TestDefinition) { // Disable lazy caching setBypassLazyCache(true); - + setDefaultIdleTimeout(100); + if (!isNode()) { let gbl = getGlobal(); if (gbl && (objHasOwn(gbl, "onunhandledrejection") || isWebWorker())) { diff --git a/lib/test/src/scheduler/scheduler.test.ts b/lib/test/src/scheduler/scheduler.test.ts index 01b47b5..a84c56b 100644 --- a/lib/test/src/scheduler/scheduler.test.ts +++ b/lib/test/src/scheduler/scheduler.test.ts @@ -18,7 +18,7 @@ import { PolyPromise } from "../../../src/polyfills/promise"; import { createResolvedPromise, setCreatePromiseImpl } from "../../../src/promise/promise"; import { setPromiseDebugState } from "../../../src/promise/debug"; import { createTaskScheduler } from "../../../src/scheduler/taskScheduler"; -import { doAwait } from "../../../src/promise/await"; +import { doAwait, doAwaitResponse } from "../../../src/promise/await"; function failOnCall(value: any) { console.error("Failed on being called " + dumpObj(value)); @@ -207,6 +207,30 @@ function batchTests(testKey: string, definition: TestDefinition) { failOnCall); }); + it("With no promise create function and single task that throws", (done) => { + let scheduler = createTaskScheduler(null as any); + assert.equal(true, scheduler.idle, "The scheduler should be idle"); + + let waitPromise = scheduler.queue(() => { + throw 42; + } ); + assert.ok(isPromiseLike(waitPromise), "We must have got a promise"); + if (checkState) { + assert.equal(waitPromise.state, "rejected"); + } + + doAwaitResponse(waitPromise, (result) => { + if (result.rejected) { + assert.equal(result.reason, 42); + } else { + assert.fail("Should have been rejected"); + } + + assert.equal(true, scheduler.idle, "The scheduler should be idle"); + done(); + }); + }); + it("With no promise create function and single delayed resolved task", (done) => { let scheduler = createTaskScheduler(null as any); assert.equal(true, scheduler.idle, "The scheduler should be idle"); diff --git a/package.json b/package.json index ffda26f..243bc12 100644 --- a/package.json +++ b/package.json @@ -78,7 +78,7 @@ "node": ">= 0.8.0" }, "dependencies": { - "@nevware21/ts-utils": ">= 0.10.3 < 2.x" + "@nevware21/ts-utils": ">= 0.10.5 < 2.x" }, "devDependencies": { "@istanbuljs/nyc-config-typescript": "^1.0.2", @@ -112,7 +112,7 @@ { "name": "es5-full", "path": "lib/dist-es5/index.js", - "limit": "14 kb", + "limit": "16 kb", "brotli": false, "ignore": [ "lib/dist-es5/polyfills.js", @@ -122,7 +122,7 @@ { "name": "es6-full", "path": "lib/dist-es6/index.js", - "limit": "14 kb", + "limit": "15 kb", "brotli": false, "ignore": [ "lib/dist-es6/polyfills.js", @@ -132,7 +132,7 @@ { "name": "es5-zip", "path": "lib/dist-es5/index.js", - "limit": "6 Kb", + "limit": "7 Kb", "gzip": true, "ignore": [ "lib/dist-es5/polyfills.js", @@ -142,7 +142,7 @@ { "name": "es6-zip", "path": "lib/dist-es6/index.js", - "limit": "6 Kb", + "limit": "7 Kb", "gzip": true, "ignore": [ "lib/dist-es6/polyfills.js", diff --git a/rush.json b/rush.json index a1fd4ce..b44fee0 100644 --- a/rush.json +++ b/rush.json @@ -3,7 +3,7 @@ "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush.schema.json", "npmVersion": "8.19.4", - "rushVersion": "5.112.2", + "rushVersion": "5.113.4", "projectFolderMaxDepth": 4, "projects": [ { diff --git a/tools/build-tools/pre-proc/package.json b/tools/build-tools/pre-proc/package.json index 2fb6a0d..b5e8944 100644 --- a/tools/build-tools/pre-proc/package.json +++ b/tools/build-tools/pre-proc/package.json @@ -21,7 +21,7 @@ "homepage": "https://github.com/nevware21/ts-async", "dependencies": { "globby": "^11.0.0", - "@nevware21/ts-utils": ">= 0.10.3 < 2.x" + "@nevware21/ts-utils": ">= 0.10.5 < 2.x" }, "devDependencies": { "@types/node": "^18.14.2",