mirror of
https://github.com/robonen/tools.git
synced 2026-03-20 10:54:44 +00:00
Compare commits
5 Commits
renovate/j
...
copilot/ad
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4d9bd6fea1 | ||
|
|
6b2707e24a | ||
|
|
da17d2d068 | ||
|
|
d9e9ee4e7f | ||
|
|
0b64e91eba |
69
core/stdlib/src/async/cancellablePromise/index.test.ts
Normal file
69
core/stdlib/src/async/cancellablePromise/index.test.ts
Normal file
@@ -0,0 +1,69 @@
|
||||
import { describe, it, expect, vi } from 'vitest';
|
||||
import { cancellablePromise, CancelledError } from '.';
|
||||
|
||||
describe('cancellablePromise', () => {
|
||||
it('resolve the promise normally when not cancelled', async () => {
|
||||
const { promise } = cancellablePromise(Promise.resolve('data'));
|
||||
|
||||
await expect(promise).resolves.toBe('data');
|
||||
});
|
||||
|
||||
it('reject the promise normally when not cancelled', async () => {
|
||||
const error = new Error('test-error');
|
||||
const { promise } = cancellablePromise(Promise.reject(error));
|
||||
|
||||
await expect(promise).rejects.toThrow(error);
|
||||
});
|
||||
|
||||
it('reject with CancelledError when cancelled before resolve', async () => {
|
||||
const { promise, cancel } = cancellablePromise(
|
||||
new Promise<string>((resolve) => setTimeout(() => resolve('data'), 100)),
|
||||
);
|
||||
|
||||
cancel();
|
||||
|
||||
await expect(promise).rejects.toBeInstanceOf(CancelledError);
|
||||
await expect(promise).rejects.toThrow('Promise was cancelled');
|
||||
});
|
||||
|
||||
it('reject with CancelledError with custom reason', async () => {
|
||||
const { promise, cancel } = cancellablePromise(
|
||||
new Promise<string>((resolve) => setTimeout(() => resolve('data'), 100)),
|
||||
);
|
||||
|
||||
cancel('Request aborted');
|
||||
|
||||
await expect(promise).rejects.toBeInstanceOf(CancelledError);
|
||||
await expect(promise).rejects.toThrow('Request aborted');
|
||||
});
|
||||
|
||||
it('cancel prevents then callback from being called', async () => {
|
||||
const onFulfilled = vi.fn();
|
||||
|
||||
const { promise, cancel } = cancellablePromise(
|
||||
new Promise<string>((resolve) => setTimeout(() => resolve('data'), 100)),
|
||||
);
|
||||
|
||||
const chained = promise.then(onFulfilled).catch(() => {});
|
||||
|
||||
cancel();
|
||||
|
||||
await chained;
|
||||
|
||||
expect(onFulfilled).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('CancelledError has correct name property', () => {
|
||||
const error = new CancelledError();
|
||||
|
||||
expect(error.name).toBe('CancelledError');
|
||||
expect(error).toBeInstanceOf(Error);
|
||||
expect(error.message).toBe('Promise was cancelled');
|
||||
});
|
||||
|
||||
it('CancelledError accepts custom message', () => {
|
||||
const error = new CancelledError('Custom reason');
|
||||
|
||||
expect(error.message).toBe('Custom reason');
|
||||
});
|
||||
});
|
||||
49
core/stdlib/src/async/cancellablePromise/index.ts
Normal file
49
core/stdlib/src/async/cancellablePromise/index.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
export class CancelledError extends Error {
|
||||
constructor(reason?: string) {
|
||||
super(reason ?? 'Promise was cancelled');
|
||||
this.name = 'CancelledError';
|
||||
}
|
||||
}
|
||||
|
||||
export interface CancellablePromise<T> {
|
||||
promise: Promise<T>;
|
||||
cancel: (reason?: string) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* @name cancellablePromise
|
||||
* @category Async
|
||||
* @description Wraps a promise with a cancel capability, allowing the promise to be rejected with a CancelledError
|
||||
*
|
||||
* @param {Promise<T>} promise - The promise to make cancellable
|
||||
* @returns {CancellablePromise<T>} - An object with the wrapped promise and a cancel function
|
||||
*
|
||||
* @example
|
||||
* const { promise, cancel } = cancellablePromise(fetch('/api/data'));
|
||||
* cancel(); // Rejects with CancelledError
|
||||
*
|
||||
* @example
|
||||
* const { promise, cancel } = cancellablePromise(longRunningTask());
|
||||
* setTimeout(() => cancel('Timeout'), 5000);
|
||||
* const [error] = await tryIt(() => promise)();
|
||||
*
|
||||
* @since 0.0.10
|
||||
*/
|
||||
export function cancellablePromise<T>(promise: Promise<T>): CancellablePromise<T> {
|
||||
let rejectPromise: (reason: CancelledError) => void;
|
||||
|
||||
const wrappedPromise = new Promise<T>((resolve, reject) => {
|
||||
rejectPromise = reject;
|
||||
|
||||
promise.then(resolve, reject);
|
||||
});
|
||||
|
||||
const cancel = (reason?: string) => {
|
||||
rejectPromise(new CancelledError(reason));
|
||||
};
|
||||
|
||||
return {
|
||||
promise: wrappedPromise,
|
||||
cancel,
|
||||
};
|
||||
}
|
||||
@@ -1,2 +1,3 @@
|
||||
export * from './cancellablePromise';
|
||||
export * from './sleep';
|
||||
export * from './tryIt';
|
||||
|
||||
183
pnpm-lock.yaml
generated
183
pnpm-lock.yaml
generated
@@ -16,8 +16,8 @@ catalogs:
|
||||
specifier: ^2.4.6
|
||||
version: 2.4.6
|
||||
jsdom:
|
||||
specifier: ^29.0.1
|
||||
version: 29.0.1
|
||||
specifier: ^28.0.0
|
||||
version: 28.0.0
|
||||
oxlint:
|
||||
specifier: ^1.2.0
|
||||
version: 1.47.0
|
||||
@@ -52,13 +52,13 @@ importers:
|
||||
version: 2.6.1
|
||||
jsdom:
|
||||
specifier: 'catalog:'
|
||||
version: 29.0.1
|
||||
version: 28.0.0
|
||||
scule:
|
||||
specifier: ^1.3.0
|
||||
version: 1.3.0
|
||||
vitest:
|
||||
specifier: 'catalog:'
|
||||
version: 4.0.18(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(@vitest/ui@4.0.18)(jiti@2.6.1)(jsdom@29.0.1)(terser@5.44.0)(yaml@2.8.2)
|
||||
version: 4.0.18(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(@vitest/ui@4.0.18)(jiti@2.6.1)(jsdom@28.0.0)(terser@5.44.0)(yaml@2.8.2)
|
||||
|
||||
configs/oxlint:
|
||||
devDependencies:
|
||||
@@ -164,16 +164,17 @@ importers:
|
||||
|
||||
packages:
|
||||
|
||||
'@acemir/cssom@0.9.31':
|
||||
resolution: {integrity: sha512-ZnR3GSaH+/vJ0YlHau21FjfLYjMpYVIzTD8M8vIEQvIGxeOXyXdzCI140rrCY862p/C/BbzWsjc1dgnM9mkoTA==}
|
||||
|
||||
'@arcanis/slice-ansi@1.1.1':
|
||||
resolution: {integrity: sha512-xguP2WR2Dv0gQ7Ykbdb7BNCnPnIPB94uTi0Z2NvkRBEnhbwjOQ7QyQKJXrVQg4qDpiD9hA5l5cCwy/z2OXgc3w==}
|
||||
|
||||
'@asamuzakjp/css-color@5.0.1':
|
||||
resolution: {integrity: sha512-2SZFvqMyvboVV1d15lMf7XiI3m7SDqXUuKaTymJYLN6dSGadqp+fVojqJlVoMlbZnlTmu3S0TLwLTJpvBMO1Aw==}
|
||||
engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
|
||||
'@asamuzakjp/css-color@4.1.2':
|
||||
resolution: {integrity: sha512-NfBUvBaYgKIuq6E/RBLY1m0IohzNHAYyaJGuTK79Z23uNwmz2jl1mPsC5ZxCCxylinKhT1Amn5oNTlx1wN8cQg==}
|
||||
|
||||
'@asamuzakjp/dom-selector@7.0.3':
|
||||
resolution: {integrity: sha512-Q6mU0Z6bfj6YvnX2k9n0JxiIwrCFN59x/nWmYQnAqP000ruX/yV+5bp/GRcF5T8ncvfwJQ7fgfP74DlpKExILA==}
|
||||
engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
|
||||
'@asamuzakjp/dom-selector@6.7.8':
|
||||
resolution: {integrity: sha512-stisC1nULNc9oH5lakAj8MH88ZxeGxzyWNDfbdCxvJSJIvDsHNZqYvscGTgy/ysgXWLJPt6K/4t0/GjvtKcFJQ==}
|
||||
|
||||
'@asamuzakjp/nwsapi@2.3.9':
|
||||
resolution: {integrity: sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==}
|
||||
@@ -433,10 +434,6 @@ packages:
|
||||
resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
'@bramus/specificity@2.4.2':
|
||||
resolution: {integrity: sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==}
|
||||
hasBin: true
|
||||
|
||||
'@breejs/later@4.2.0':
|
||||
resolution: {integrity: sha512-EVMD0SgJtOuFeg0lAVbCwa+qeTKILb87jqvLyUtQswGD9+ce2nB52Y5zbTF1Hc0MDFfbydcMcxb47jSdhikVHA==}
|
||||
engines: {node: '>= 10'}
|
||||
@@ -444,8 +441,8 @@ packages:
|
||||
'@cdktf/hcl2json@0.21.0':
|
||||
resolution: {integrity: sha512-cwX3i/mSJI/cRrtqwEPRfawB7pXgNioriSlkvou8LWiCrrcDe9ZtTbAbu8W1tEJQpe1pnX9VEgpzf/BbM7xF8Q==}
|
||||
|
||||
'@csstools/color-helpers@6.0.2':
|
||||
resolution: {integrity: sha512-LMGQLS9EuADloEFkcTBR3BwV/CGHV7zyDxVRtVDTwdI2Ca4it0CCVTT9wCkxSgokjE5Ho41hEPgb8OEUwoXr6Q==}
|
||||
'@csstools/color-helpers@6.0.1':
|
||||
resolution: {integrity: sha512-NmXRccUJMk2AWA5A7e5a//3bCIMyOu2hAtdRYrhPPHjDxINuCwX1w6rnIZ4xjLcp0ayv6h8Pc3X0eJUGiAAXHQ==}
|
||||
engines: {node: '>=20.19.0'}
|
||||
|
||||
'@csstools/css-calc@3.1.1':
|
||||
@@ -455,8 +452,8 @@ packages:
|
||||
'@csstools/css-parser-algorithms': ^4.0.0
|
||||
'@csstools/css-tokenizer': ^4.0.0
|
||||
|
||||
'@csstools/css-color-parser@4.0.2':
|
||||
resolution: {integrity: sha512-0GEfbBLmTFf0dJlpsNU7zwxRIH0/BGEMuXLTCvFYxuL1tNhqzTbtnFICyJLTNK4a+RechKP75e7w42ClXSnJQw==}
|
||||
'@csstools/css-color-parser@4.0.1':
|
||||
resolution: {integrity: sha512-vYwO15eRBEkeF6xjAno/KQ61HacNhfQuuU/eGwH67DplL0zD5ZixUa563phQvUelA07yDczIXdtmYojCphKJcw==}
|
||||
engines: {node: '>=20.19.0'}
|
||||
peerDependencies:
|
||||
'@csstools/css-parser-algorithms': ^4.0.0
|
||||
@@ -468,13 +465,8 @@ packages:
|
||||
peerDependencies:
|
||||
'@csstools/css-tokenizer': ^4.0.0
|
||||
|
||||
'@csstools/css-syntax-patches-for-csstree@1.1.1':
|
||||
resolution: {integrity: sha512-BvqN0AMWNAnLk9G8jnUT77D+mUbY/H2b3uDTvg2isJkHaOufUE2R3AOwxWo7VBQKT1lOdwdvorddo2B/lk64+w==}
|
||||
peerDependencies:
|
||||
css-tree: ^3.2.1
|
||||
peerDependenciesMeta:
|
||||
css-tree:
|
||||
optional: true
|
||||
'@csstools/css-syntax-patches-for-csstree@1.0.27':
|
||||
resolution: {integrity: sha512-sxP33Jwg1bviSUXAV43cVYdmjt2TLnLXNqCWl9xmxHawWVjGz/kEbdkr7F9pxJNBN2Mh+dq0crgItbW6tQvyow==}
|
||||
|
||||
'@csstools/css-tokenizer@4.0.0':
|
||||
resolution: {integrity: sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==}
|
||||
@@ -645,8 +637,8 @@ packages:
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@exodus/bytes@1.15.0':
|
||||
resolution: {integrity: sha512-UY0nlA+feH81UGSHv92sLEPLCeZFjXOuHhrIo0HQydScuQc8s0A7kL/UdgwgDq8g8ilksmuoF35YVTNphV2aBQ==}
|
||||
'@exodus/bytes@1.14.1':
|
||||
resolution: {integrity: sha512-OhkBFWI6GcRMUroChZiopRiSp2iAMvEBK47NhJooDqz1RERO4QuZIZnjP63TXX8GAiLABkYmX+fuQsdJ1dd2QQ==}
|
||||
engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
|
||||
peerDependencies:
|
||||
'@noble/hashes': ^1.8.0 || ^2.0.0
|
||||
@@ -2059,14 +2051,18 @@ packages:
|
||||
css-select@5.1.0:
|
||||
resolution: {integrity: sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==}
|
||||
|
||||
css-tree@3.2.1:
|
||||
resolution: {integrity: sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==}
|
||||
css-tree@3.1.0:
|
||||
resolution: {integrity: sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==}
|
||||
engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0}
|
||||
|
||||
css-what@6.1.0:
|
||||
resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==}
|
||||
engines: {node: '>= 6'}
|
||||
|
||||
cssstyle@5.3.7:
|
||||
resolution: {integrity: sha512-7D2EPVltRrsTkhpQmksIu+LxeWAIEk6wRDMJ1qljlv+CKHJM+cJLlfhWIzNA44eAsHXSNe3+vO6DW1yCYx8SuQ==}
|
||||
engines: {node: '>=20'}
|
||||
|
||||
csstype@3.2.3:
|
||||
resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==}
|
||||
|
||||
@@ -2468,7 +2464,6 @@ packages:
|
||||
git-raw-commits@2.0.11:
|
||||
resolution: {integrity: sha512-VnctFhw+xfj8Va1xtfEqCUD2XDrbAPSJx+hSrE5K7fGdjZruW7XV+QOrN7LF/RJyvspRiD2I0asWsxFp0ya26A==}
|
||||
engines: {node: '>=10'}
|
||||
deprecated: This package is no longer maintained. For the JavaScript API, please use @conventional-changelog/git-client instead.
|
||||
hasBin: true
|
||||
|
||||
git-up@8.1.1:
|
||||
@@ -2792,9 +2787,9 @@ packages:
|
||||
jsbn@1.1.0:
|
||||
resolution: {integrity: sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==}
|
||||
|
||||
jsdom@29.0.1:
|
||||
resolution: {integrity: sha512-z6JOK5gRO7aMybVq/y/MlIpKh8JIi68FBKMUtKkK2KH/wMSRlCxQ682d08LB9fYXplyY/UXG8P4XXTScmdjApg==}
|
||||
engines: {node: ^20.19.0 || ^22.13.0 || >=24.0.0}
|
||||
jsdom@28.0.0:
|
||||
resolution: {integrity: sha512-KDYJgZ6T2TKdU8yBfYueq5EPG/EylMsBvCaenWMJb2OXmjgczzwveRCoJ+Hgj1lXPDyasvrgneSn4GBuR1hYyA==}
|
||||
engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
|
||||
peerDependencies:
|
||||
canvas: ^3.0.0
|
||||
peerDependenciesMeta:
|
||||
@@ -2892,12 +2887,12 @@ packages:
|
||||
lru-cache@10.4.3:
|
||||
resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
|
||||
|
||||
lru-cache@11.2.6:
|
||||
resolution: {integrity: sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==}
|
||||
lru-cache@11.2.1:
|
||||
resolution: {integrity: sha512-r8LA6i4LP4EeWOhqBaZZjDWwehd1xUJPCJd9Sv300H0ZmcUER4+JPh7bqqZeqs1o5pgtgvXm+d9UGrB5zZGDiQ==}
|
||||
engines: {node: 20 || >=22}
|
||||
|
||||
lru-cache@11.2.7:
|
||||
resolution: {integrity: sha512-aY/R+aEsRelme17KGQa/1ZSIpLpNYYrhcrepKTZgE+W3WM16YMCaPwOHLHsmopZHELU0Ojin1lPVxKR0MihncA==}
|
||||
lru-cache@11.2.6:
|
||||
resolution: {integrity: sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==}
|
||||
engines: {node: 20 || >=22}
|
||||
|
||||
lru-cache@6.0.0:
|
||||
@@ -2974,8 +2969,8 @@ packages:
|
||||
mdast-util-to-string@4.0.0:
|
||||
resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==}
|
||||
|
||||
mdn-data@2.27.1:
|
||||
resolution: {integrity: sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==}
|
||||
mdn-data@2.12.2:
|
||||
resolution: {integrity: sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==}
|
||||
|
||||
mdurl@2.0.0:
|
||||
resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==}
|
||||
@@ -3456,7 +3451,6 @@ packages:
|
||||
prebuild-install@7.1.2:
|
||||
resolution: {integrity: sha512-UnNke3IQb6sgarcZIDU3gbMeTp/9SSU1DAIkil7PrqG1vZlBtY5msYccSKSHDqa3hNg436IXK+SNImReuA1wEQ==}
|
||||
engines: {node: '>=10'}
|
||||
deprecated: No longer maintained. Please contact the author of the relevant native addon; alternatives are available.
|
||||
hasBin: true
|
||||
|
||||
prettier@3.6.2:
|
||||
@@ -3883,7 +3877,6 @@ packages:
|
||||
tar@7.5.7:
|
||||
resolution: {integrity: sha512-fov56fJiRuThVFXD6o6/Q354S7pnWMJIVlDBYijsTNx6jKSE4pvrDTs6lUnmGvNyfJwFQQwWy3owKz1ucIhveQ==}
|
||||
engines: {node: '>=18'}
|
||||
deprecated: Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me
|
||||
|
||||
terser@5.44.0:
|
||||
resolution: {integrity: sha512-nIVck8DK+GM/0Frwd+nIhZ84pR/BX7rmXMfYwyg+Sri5oGVE99/E3KvXqpC2xHFxyqXyGHTKBSioxxplrO4I4w==}
|
||||
@@ -3943,8 +3936,8 @@ packages:
|
||||
resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
tough-cookie@6.0.1:
|
||||
resolution: {integrity: sha512-LktZQb3IeoUWB9lqR5EWTHgW/VTITCXg4D21M+lvybRVdylLrRMnqaIONLVb5mav8vM19m44HIcGq4qASeu2Qw==}
|
||||
tough-cookie@6.0.0:
|
||||
resolution: {integrity: sha512-kXuRi1mtaKMrsLUxz3sQYvVl37B0Ns6MzfrtV5DvJceE9bPyspOqk9xxv7XbZWcfLWbFmm997vl83qUWVJA64w==}
|
||||
engines: {node: '>=16'}
|
||||
|
||||
tr46@0.0.3:
|
||||
@@ -4048,8 +4041,8 @@ packages:
|
||||
undici-types@7.16.0:
|
||||
resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==}
|
||||
|
||||
undici@7.24.5:
|
||||
resolution: {integrity: sha512-3IWdCpjgxp15CbJnsi/Y9TCDE7HWVN19j1hmzVhoAkY/+CJx449tVxT5wZc1Gwg8J+P0LWvzlBzxYRnHJ+1i7Q==}
|
||||
undici@7.21.0:
|
||||
resolution: {integrity: sha512-Hn2tCQpoDt1wv23a68Ctc8Cr/BHpUSfaPYrkajTXOS9IKpxVRx/X5m1K2YkbK2ipgZgxXSgsUinl3x+2YdSSfg==}
|
||||
engines: {node: '>=20.18.1'}
|
||||
|
||||
unicorn-magic@0.3.0:
|
||||
@@ -4222,8 +4215,8 @@ packages:
|
||||
resolution: {integrity: sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==}
|
||||
engines: {node: '>=20'}
|
||||
|
||||
whatwg-url@16.0.1:
|
||||
resolution: {integrity: sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw==}
|
||||
whatwg-url@16.0.0:
|
||||
resolution: {integrity: sha512-9CcxtEKsf53UFwkSUZjG+9vydAsFO4lFHBpJUtjBcoJOCJpKnSJNwCw813zrYJHpCJ7sgfbtOe0V5Ku7Pa1XMQ==}
|
||||
engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
|
||||
|
||||
whatwg-url@5.0.0:
|
||||
@@ -4323,25 +4316,27 @@ packages:
|
||||
|
||||
snapshots:
|
||||
|
||||
'@acemir/cssom@0.9.31': {}
|
||||
|
||||
'@arcanis/slice-ansi@1.1.1':
|
||||
dependencies:
|
||||
grapheme-splitter: 1.0.4
|
||||
|
||||
'@asamuzakjp/css-color@5.0.1':
|
||||
'@asamuzakjp/css-color@4.1.2':
|
||||
dependencies:
|
||||
'@csstools/css-calc': 3.1.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)
|
||||
'@csstools/css-color-parser': 4.0.2(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)
|
||||
'@csstools/css-color-parser': 4.0.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)
|
||||
'@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0)
|
||||
'@csstools/css-tokenizer': 4.0.0
|
||||
lru-cache: 11.2.7
|
||||
lru-cache: 11.2.6
|
||||
|
||||
'@asamuzakjp/dom-selector@7.0.3':
|
||||
'@asamuzakjp/dom-selector@6.7.8':
|
||||
dependencies:
|
||||
'@asamuzakjp/nwsapi': 2.3.9
|
||||
bidi-js: 1.0.3
|
||||
css-tree: 3.2.1
|
||||
css-tree: 3.1.0
|
||||
is-potential-custom-element-name: 1.0.1
|
||||
lru-cache: 11.2.7
|
||||
lru-cache: 11.2.6
|
||||
|
||||
'@asamuzakjp/nwsapi@2.3.9': {}
|
||||
|
||||
@@ -5252,26 +5247,22 @@ snapshots:
|
||||
|
||||
'@bcoe/v8-coverage@1.0.2': {}
|
||||
|
||||
'@bramus/specificity@2.4.2':
|
||||
dependencies:
|
||||
css-tree: 3.2.1
|
||||
|
||||
'@breejs/later@4.2.0': {}
|
||||
|
||||
'@cdktf/hcl2json@0.21.0':
|
||||
dependencies:
|
||||
fs-extra: 11.3.0
|
||||
|
||||
'@csstools/color-helpers@6.0.2': {}
|
||||
'@csstools/color-helpers@6.0.1': {}
|
||||
|
||||
'@csstools/css-calc@3.1.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)':
|
||||
dependencies:
|
||||
'@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0)
|
||||
'@csstools/css-tokenizer': 4.0.0
|
||||
|
||||
'@csstools/css-color-parser@4.0.2(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)':
|
||||
'@csstools/css-color-parser@4.0.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)':
|
||||
dependencies:
|
||||
'@csstools/color-helpers': 6.0.2
|
||||
'@csstools/color-helpers': 6.0.1
|
||||
'@csstools/css-calc': 3.1.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)
|
||||
'@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0)
|
||||
'@csstools/css-tokenizer': 4.0.0
|
||||
@@ -5280,9 +5271,7 @@ snapshots:
|
||||
dependencies:
|
||||
'@csstools/css-tokenizer': 4.0.0
|
||||
|
||||
'@csstools/css-syntax-patches-for-csstree@1.1.1(css-tree@3.2.1)':
|
||||
optionalDependencies:
|
||||
css-tree: 3.2.1
|
||||
'@csstools/css-syntax-patches-for-csstree@1.0.27': {}
|
||||
|
||||
'@csstools/css-tokenizer@4.0.0': {}
|
||||
|
||||
@@ -5380,7 +5369,7 @@ snapshots:
|
||||
'@esbuild/win32-x64@0.25.9':
|
||||
optional: true
|
||||
|
||||
'@exodus/bytes@1.15.0': {}
|
||||
'@exodus/bytes@1.14.1': {}
|
||||
|
||||
'@gwhitney/detect-indent@7.0.1': {}
|
||||
|
||||
@@ -5456,7 +5445,7 @@ snapshots:
|
||||
agent-base: 7.1.3
|
||||
http-proxy-agent: 7.0.2
|
||||
https-proxy-agent: 7.0.6
|
||||
lru-cache: 11.2.6
|
||||
lru-cache: 11.2.1
|
||||
socks-proxy-agent: 8.0.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
@@ -6417,7 +6406,7 @@ snapshots:
|
||||
obug: 2.1.1
|
||||
std-env: 3.10.0
|
||||
tinyrainbow: 3.0.3
|
||||
vitest: 4.0.18(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(@vitest/ui@4.0.18)(jiti@2.6.1)(jsdom@29.0.1)(terser@5.44.0)(yaml@2.8.2)
|
||||
vitest: 4.0.18(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(@vitest/ui@4.0.18)(jiti@2.6.1)(jsdom@28.0.0)(terser@5.44.0)(yaml@2.8.2)
|
||||
|
||||
'@vitest/expect@4.0.18':
|
||||
dependencies:
|
||||
@@ -6462,7 +6451,7 @@ snapshots:
|
||||
sirv: 3.0.2
|
||||
tinyglobby: 0.2.15
|
||||
tinyrainbow: 3.0.3
|
||||
vitest: 4.0.18(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(@vitest/ui@4.0.18)(jiti@2.6.1)(jsdom@29.0.1)(terser@5.44.0)(yaml@2.8.2)
|
||||
vitest: 4.0.18(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(@vitest/ui@4.0.18)(jiti@2.6.1)(jsdom@28.0.0)(terser@5.44.0)(yaml@2.8.2)
|
||||
|
||||
'@vitest/utils@4.0.18':
|
||||
dependencies:
|
||||
@@ -6740,7 +6729,7 @@ snapshots:
|
||||
'@npmcli/fs': 5.0.0
|
||||
fs-minipass: 3.0.3
|
||||
glob: 13.0.1
|
||||
lru-cache: 11.2.6
|
||||
lru-cache: 11.2.1
|
||||
minipass: 7.1.2
|
||||
minipass-collect: 2.0.1
|
||||
minipass-flush: 1.0.5
|
||||
@@ -6870,13 +6859,20 @@ snapshots:
|
||||
domutils: 3.1.0
|
||||
nth-check: 2.1.1
|
||||
|
||||
css-tree@3.2.1:
|
||||
css-tree@3.1.0:
|
||||
dependencies:
|
||||
mdn-data: 2.27.1
|
||||
mdn-data: 2.12.2
|
||||
source-map-js: 1.2.1
|
||||
|
||||
css-what@6.1.0: {}
|
||||
|
||||
cssstyle@5.3.7:
|
||||
dependencies:
|
||||
'@asamuzakjp/css-color': 4.1.2
|
||||
'@csstools/css-syntax-patches-for-csstree': 1.0.27
|
||||
css-tree: 3.1.0
|
||||
lru-cache: 11.2.6
|
||||
|
||||
csstype@3.2.3: {}
|
||||
|
||||
dargs@7.0.0: {}
|
||||
@@ -6886,7 +6882,7 @@ snapshots:
|
||||
data-urls@7.0.0:
|
||||
dependencies:
|
||||
whatwg-mimetype: 5.0.0
|
||||
whatwg-url: 16.0.1
|
||||
whatwg-url: 16.0.0
|
||||
transitivePeerDependencies:
|
||||
- '@noble/hashes'
|
||||
|
||||
@@ -7440,7 +7436,7 @@ snapshots:
|
||||
|
||||
html-encoding-sniffer@6.0.0:
|
||||
dependencies:
|
||||
'@exodus/bytes': 1.15.0
|
||||
'@exodus/bytes': 1.14.1
|
||||
transitivePeerDependencies:
|
||||
- '@noble/hashes'
|
||||
|
||||
@@ -7454,7 +7450,6 @@ snapshots:
|
||||
debug: 4.4.1
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
optional: true
|
||||
|
||||
http2-wrapper@1.0.3:
|
||||
dependencies:
|
||||
@@ -7625,31 +7620,31 @@ snapshots:
|
||||
jsbn@1.1.0:
|
||||
optional: true
|
||||
|
||||
jsdom@29.0.1:
|
||||
jsdom@28.0.0:
|
||||
dependencies:
|
||||
'@asamuzakjp/css-color': 5.0.1
|
||||
'@asamuzakjp/dom-selector': 7.0.3
|
||||
'@bramus/specificity': 2.4.2
|
||||
'@csstools/css-syntax-patches-for-csstree': 1.1.1(css-tree@3.2.1)
|
||||
'@exodus/bytes': 1.15.0
|
||||
css-tree: 3.2.1
|
||||
'@acemir/cssom': 0.9.31
|
||||
'@asamuzakjp/dom-selector': 6.7.8
|
||||
'@exodus/bytes': 1.14.1
|
||||
cssstyle: 5.3.7
|
||||
data-urls: 7.0.0
|
||||
decimal.js: 10.6.0
|
||||
html-encoding-sniffer: 6.0.0
|
||||
http-proxy-agent: 7.0.2
|
||||
https-proxy-agent: 7.0.6
|
||||
is-potential-custom-element-name: 1.0.1
|
||||
lru-cache: 11.2.7
|
||||
parse5: 8.0.0
|
||||
saxes: 6.0.0
|
||||
symbol-tree: 3.2.4
|
||||
tough-cookie: 6.0.1
|
||||
undici: 7.24.5
|
||||
tough-cookie: 6.0.0
|
||||
undici: 7.21.0
|
||||
w3c-xmlserializer: 5.0.0
|
||||
webidl-conversions: 8.0.1
|
||||
whatwg-mimetype: 5.0.0
|
||||
whatwg-url: 16.0.1
|
||||
whatwg-url: 16.0.0
|
||||
xml-name-validator: 5.0.0
|
||||
transitivePeerDependencies:
|
||||
- '@noble/hashes'
|
||||
- supports-color
|
||||
|
||||
jsesc@3.1.0: {}
|
||||
|
||||
@@ -7732,9 +7727,9 @@ snapshots:
|
||||
|
||||
lru-cache@10.4.3: {}
|
||||
|
||||
lru-cache@11.2.6: {}
|
||||
lru-cache@11.2.1: {}
|
||||
|
||||
lru-cache@11.2.7: {}
|
||||
lru-cache@11.2.6: {}
|
||||
|
||||
lru-cache@6.0.0:
|
||||
dependencies:
|
||||
@@ -7894,7 +7889,7 @@ snapshots:
|
||||
dependencies:
|
||||
'@types/mdast': 4.0.4
|
||||
|
||||
mdn-data@2.27.1: {}
|
||||
mdn-data@2.12.2: {}
|
||||
|
||||
mdurl@2.0.0: {}
|
||||
|
||||
@@ -8465,7 +8460,7 @@ snapshots:
|
||||
|
||||
path-scurry@2.0.0:
|
||||
dependencies:
|
||||
lru-cache: 11.2.6
|
||||
lru-cache: 11.2.1
|
||||
minipass: 7.1.2
|
||||
|
||||
pathe@2.0.3: {}
|
||||
@@ -9216,7 +9211,7 @@ snapshots:
|
||||
|
||||
totalist@3.0.1: {}
|
||||
|
||||
tough-cookie@6.0.1:
|
||||
tough-cookie@6.0.0:
|
||||
dependencies:
|
||||
tldts: 7.0.23
|
||||
|
||||
@@ -9311,7 +9306,7 @@ snapshots:
|
||||
|
||||
undici-types@7.16.0: {}
|
||||
|
||||
undici@7.24.5: {}
|
||||
undici@7.21.0: {}
|
||||
|
||||
unicorn-magic@0.3.0: {}
|
||||
|
||||
@@ -9406,7 +9401,7 @@ snapshots:
|
||||
terser: 5.44.0
|
||||
yaml: 2.8.2
|
||||
|
||||
vitest@4.0.18(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(@vitest/ui@4.0.18)(jiti@2.6.1)(jsdom@29.0.1)(terser@5.44.0)(yaml@2.8.2):
|
||||
vitest@4.0.18(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(@vitest/ui@4.0.18)(jiti@2.6.1)(jsdom@28.0.0)(terser@5.44.0)(yaml@2.8.2):
|
||||
dependencies:
|
||||
'@vitest/expect': 4.0.18
|
||||
'@vitest/mocker': 4.0.18(vite@7.1.4(@types/node@24.10.13)(jiti@2.6.1)(terser@5.44.0)(yaml@2.8.2))
|
||||
@@ -9432,7 +9427,7 @@ snapshots:
|
||||
'@opentelemetry/api': 1.9.0
|
||||
'@types/node': 24.10.13
|
||||
'@vitest/ui': 4.0.18(vitest@4.0.18)
|
||||
jsdom: 29.0.1
|
||||
jsdom: 28.0.0
|
||||
transitivePeerDependencies:
|
||||
- jiti
|
||||
- less
|
||||
@@ -9470,9 +9465,9 @@ snapshots:
|
||||
|
||||
whatwg-mimetype@5.0.0: {}
|
||||
|
||||
whatwg-url@16.0.1:
|
||||
whatwg-url@16.0.0:
|
||||
dependencies:
|
||||
'@exodus/bytes': 1.15.0
|
||||
'@exodus/bytes': 1.14.1
|
||||
tr46: 6.0.0
|
||||
webidl-conversions: 8.0.1
|
||||
transitivePeerDependencies:
|
||||
|
||||
@@ -8,7 +8,7 @@ packages:
|
||||
catalog:
|
||||
'@vitest/coverage-v8': ^4.0.18
|
||||
'@vue/test-utils': ^2.4.6
|
||||
jsdom: ^29.0.1
|
||||
jsdom: ^28.0.0
|
||||
oxlint: ^1.2.0
|
||||
tsdown: ^0.12.5
|
||||
vitest: ^4.0.18
|
||||
|
||||
@@ -22,6 +22,7 @@ describe(useAsyncState, () => {
|
||||
expect(isLoading.value).toBeTruthy();
|
||||
expect(error.value).toBe(null);
|
||||
|
||||
await nextTick();
|
||||
await nextTick();
|
||||
|
||||
expect(state.value).toBe('data');
|
||||
@@ -41,6 +42,7 @@ describe(useAsyncState, () => {
|
||||
expect(isLoading.value).toBeTruthy();
|
||||
expect(error.value).toBe(null);
|
||||
|
||||
await nextTick();
|
||||
await nextTick();
|
||||
|
||||
expect(state.value).toBe('data');
|
||||
@@ -60,6 +62,7 @@ describe(useAsyncState, () => {
|
||||
expect(isLoading.value).toBeTruthy();
|
||||
expect(error.value).toBe(null);
|
||||
|
||||
await nextTick();
|
||||
await nextTick();
|
||||
|
||||
expect(state.value).toBe('initial');
|
||||
@@ -77,6 +80,7 @@ describe(useAsyncState, () => {
|
||||
{ onSuccess },
|
||||
);
|
||||
|
||||
await nextTick();
|
||||
await nextTick();
|
||||
|
||||
expect(onSuccess).toHaveBeenCalledWith('data');
|
||||
@@ -92,6 +96,7 @@ describe(useAsyncState, () => {
|
||||
{ onError },
|
||||
);
|
||||
|
||||
await nextTick();
|
||||
await nextTick();
|
||||
|
||||
expect(onError).toHaveBeenCalledWith(error);
|
||||
@@ -164,6 +169,7 @@ describe(useAsyncState, () => {
|
||||
expect(isReady.value).toBeFalsy();
|
||||
expect(error.value).toBe(null);
|
||||
|
||||
await nextTick();
|
||||
await nextTick();
|
||||
|
||||
expect(state.value).toBe('data');
|
||||
@@ -206,4 +212,114 @@ describe(useAsyncState, () => {
|
||||
expect(state.value.a).toBe(1);
|
||||
expect(isShallow(state)).toBeFalsy();
|
||||
});
|
||||
|
||||
it('aborts pending execution', async () => {
|
||||
let resolvePromise: (value: string) => void;
|
||||
const promiseFn = () => new Promise<string>(resolve => { resolvePromise = resolve; });
|
||||
|
||||
const { state, isLoading, abort, executeImmediately } = useAsyncState(
|
||||
promiseFn,
|
||||
'initial',
|
||||
{ immediate: false },
|
||||
);
|
||||
|
||||
executeImmediately();
|
||||
expect(isLoading.value).toBeTruthy();
|
||||
|
||||
abort();
|
||||
expect(isLoading.value).toBeFalsy();
|
||||
|
||||
resolvePromise!('data');
|
||||
await nextTick();
|
||||
|
||||
expect(state.value).toBe('initial');
|
||||
});
|
||||
|
||||
it('abort prevents state update from resolved promise', async () => {
|
||||
let resolvePromise: (value: string) => void;
|
||||
const promiseFn = () => new Promise<string>(resolve => { resolvePromise = resolve; });
|
||||
|
||||
const { state, isLoading, isReady, abort, executeImmediately } = useAsyncState(
|
||||
promiseFn,
|
||||
'initial',
|
||||
{ immediate: false },
|
||||
);
|
||||
|
||||
executeImmediately();
|
||||
expect(isLoading.value).toBeTruthy();
|
||||
|
||||
abort();
|
||||
expect(isLoading.value).toBeFalsy();
|
||||
|
||||
resolvePromise!('data');
|
||||
await nextTick();
|
||||
|
||||
expect(state.value).toBe('initial');
|
||||
expect(isReady.value).toBeFalsy();
|
||||
});
|
||||
|
||||
it('abort prevents error handling from rejected promise', async () => {
|
||||
let rejectPromise: (error: Error) => void;
|
||||
const promiseFn = () => new Promise<string>((_, reject) => { rejectPromise = reject; });
|
||||
const onError = vi.fn();
|
||||
|
||||
const { error, abort, executeImmediately } = useAsyncState(
|
||||
promiseFn,
|
||||
'initial',
|
||||
{ immediate: false, onError },
|
||||
);
|
||||
|
||||
executeImmediately();
|
||||
abort();
|
||||
|
||||
rejectPromise!(new Error('test-error'));
|
||||
await nextTick();
|
||||
|
||||
expect(error.value).toBe(null);
|
||||
expect(onError).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('new execute after abort works correctly', async () => {
|
||||
let resolvePromise: (value: string) => void;
|
||||
const promiseFn = () => new Promise<string>(resolve => { resolvePromise = resolve; });
|
||||
|
||||
const { state, isReady, abort, executeImmediately } = useAsyncState(
|
||||
promiseFn,
|
||||
'initial',
|
||||
{ immediate: false },
|
||||
);
|
||||
|
||||
executeImmediately();
|
||||
abort();
|
||||
|
||||
executeImmediately();
|
||||
resolvePromise!('new data');
|
||||
await nextTick();
|
||||
await nextTick();
|
||||
|
||||
expect(state.value).toBe('new data');
|
||||
expect(isReady.value).toBeTruthy();
|
||||
});
|
||||
|
||||
it('re-execute cancels previous pending execution', async () => {
|
||||
let callCount = 0;
|
||||
const promiseFn = (value: string) => new Promise<string>(resolve => {
|
||||
callCount++;
|
||||
setTimeout(() => resolve(value), 100);
|
||||
});
|
||||
|
||||
const { state, executeImmediately } = useAsyncState(
|
||||
promiseFn,
|
||||
'initial',
|
||||
{ immediate: false },
|
||||
);
|
||||
|
||||
executeImmediately('first');
|
||||
executeImmediately('second');
|
||||
|
||||
await vi.advanceTimersByTimeAsync(100);
|
||||
|
||||
expect(state.value).toBe('second');
|
||||
expect(callCount).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ref, shallowRef, watch } from 'vue';
|
||||
import type { Ref, ShallowRef, UnwrapRef } from 'vue';
|
||||
import { isFunction, sleep } from '@robonen/stdlib';
|
||||
import { isFunction, sleep, cancellablePromise as makeCancellable, CancelledError } from '@robonen/stdlib';
|
||||
|
||||
export interface UseAsyncStateOptions<Shallow extends boolean, Data = any> {
|
||||
delay?: number;
|
||||
@@ -19,6 +19,7 @@ export interface UseAsyncStateReturnBase<Data, Params extends any[], Shallow ext
|
||||
error: Ref<unknown | null>;
|
||||
execute: (delay?: number, ...params: Params) => Promise<Data>;
|
||||
executeImmediately: (...params: Params) => Promise<Data>;
|
||||
abort: () => void;
|
||||
}
|
||||
|
||||
export type UseAsyncStateReturn<Data, Params extends any[], Shallow extends boolean> =
|
||||
@@ -50,7 +51,14 @@ export function useAsyncState<Data, Params extends any[] = [], Shallow extends b
|
||||
const isLoading = ref(false);
|
||||
const isReady = ref(false);
|
||||
|
||||
let cancelPending: ((reason?: string) => void) | undefined;
|
||||
|
||||
const execute = async (actualDelay = delay, ...params: any[]) => {
|
||||
cancelPending?.();
|
||||
|
||||
let active = true;
|
||||
cancelPending = () => { active = false; };
|
||||
|
||||
if (resetOnExecute)
|
||||
state.value = initialState;
|
||||
|
||||
@@ -61,15 +69,27 @@ export function useAsyncState<Data, Params extends any[] = [], Shallow extends b
|
||||
if (actualDelay > 0)
|
||||
await sleep(actualDelay);
|
||||
|
||||
const promise = isFunction(maybePromise) ? maybePromise(...params as Params) : maybePromise;
|
||||
if (!active)
|
||||
return state.value as Data;
|
||||
|
||||
const rawPromise = isFunction(maybePromise) ? maybePromise(...params as Params) : maybePromise;
|
||||
const { promise, cancel } = makeCancellable(rawPromise);
|
||||
cancelPending = (reason?: string) => {
|
||||
active = false;
|
||||
cancel(reason);
|
||||
};
|
||||
|
||||
try {
|
||||
const data = await promise;
|
||||
|
||||
state.value = data;
|
||||
isReady.value = true;
|
||||
onSuccess?.(data);
|
||||
}
|
||||
catch (e: unknown) {
|
||||
if (e instanceof CancelledError)
|
||||
return state.value as Data;
|
||||
|
||||
error.value = e;
|
||||
onError?.(e);
|
||||
|
||||
@@ -77,6 +97,7 @@ export function useAsyncState<Data, Params extends any[] = [], Shallow extends b
|
||||
throw e;
|
||||
}
|
||||
finally {
|
||||
if (active)
|
||||
isLoading.value = false;
|
||||
}
|
||||
|
||||
@@ -87,6 +108,12 @@ export function useAsyncState<Data, Params extends any[] = [], Shallow extends b
|
||||
return execute(0, ...params);
|
||||
};
|
||||
|
||||
const abort = () => {
|
||||
cancelPending?.();
|
||||
cancelPending = undefined;
|
||||
isLoading.value = false;
|
||||
};
|
||||
|
||||
if (immediate)
|
||||
execute();
|
||||
|
||||
@@ -97,14 +124,17 @@ export function useAsyncState<Data, Params extends any[] = [], Shallow extends b
|
||||
error,
|
||||
execute,
|
||||
executeImmediately,
|
||||
abort,
|
||||
};
|
||||
|
||||
function waitResolve() {
|
||||
return new Promise<UseAsyncStateReturnBase<Data, Params, Shallow>>((resolve, reject) => {
|
||||
watch(
|
||||
const unwatch = watch(
|
||||
isLoading,
|
||||
(loading) => {
|
||||
if (loading === false) {
|
||||
unwatch();
|
||||
|
||||
if (error.value)
|
||||
reject(error.value);
|
||||
else
|
||||
@@ -113,7 +143,6 @@ export function useAsyncState<Data, Params extends any[] = [], Shallow extends b
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
once: true,
|
||||
flush: 'sync',
|
||||
},
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user