parent
d7920cae0a
commit
eb1730ba0c
|
@ -10,11 +10,12 @@ jobs:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
node-version:
|
node-version:
|
||||||
|
- 18
|
||||||
|
- 16
|
||||||
- 14
|
- 14
|
||||||
- 12
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/setup-node@v1
|
- uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node-version }}
|
node-version: ${{ matrix.node-version }}
|
||||||
- run: npm install
|
- run: npm install
|
||||||
|
|
|
@ -25,7 +25,7 @@ export type Options<ReturnType> = {
|
||||||
|
|
||||||
@example
|
@example
|
||||||
```
|
```
|
||||||
import {setTimeout} from 'timers/promises';
|
import {setTimeout} from 'node:timers/promises';
|
||||||
import pTimeout from 'p-timeout';
|
import pTimeout from 'p-timeout';
|
||||||
|
|
||||||
const delayedPromise = () => setTimeout(200);
|
const delayedPromise = () => setTimeout(200);
|
||||||
|
@ -116,7 +116,7 @@ If you pass in a cancelable promise, specifically a promise with a `.cancel()` m
|
||||||
|
|
||||||
@example
|
@example
|
||||||
```
|
```
|
||||||
import {setTimeout} from 'timers/promises';
|
import {setTimeout} from 'node:timers/promises';
|
||||||
import pTimeout from 'p-timeout';
|
import pTimeout from 'p-timeout';
|
||||||
|
|
||||||
const delayedPromise = () => setTimeout(200);
|
const delayedPromise = () => setTimeout(200);
|
||||||
|
|
32
index.js
32
index.js
|
@ -20,27 +20,32 @@ export class AbortError extends Error {
|
||||||
/**
|
/**
|
||||||
TODO: Remove AbortError and just throw DOMException when targeting Node 18.
|
TODO: Remove AbortError and just throw DOMException when targeting Node 18.
|
||||||
*/
|
*/
|
||||||
const getDOMException = errorMessage => globalThis.DOMException === undefined ?
|
const getDOMException = errorMessage => globalThis.DOMException === undefined
|
||||||
new AbortError(errorMessage) :
|
? new AbortError(errorMessage)
|
||||||
new DOMException(errorMessage);
|
: new DOMException(errorMessage);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
TODO: Remove below function and just 'reject(signal.reason)' when targeting Node 18.
|
TODO: Remove below function and just 'reject(signal.reason)' when targeting Node 18.
|
||||||
*/
|
*/
|
||||||
const getAbortedReason = signal => {
|
const getAbortedReason = signal => {
|
||||||
const reason = signal.reason === undefined ?
|
const reason = signal.reason === undefined
|
||||||
getDOMException('This operation was aborted.') :
|
? getDOMException('This operation was aborted.')
|
||||||
signal.reason;
|
: signal.reason;
|
||||||
|
|
||||||
return reason instanceof Error ? reason : getDOMException(reason);
|
return reason instanceof Error ? reason : getDOMException(reason);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function pTimeout(promise, options) {
|
export default function pTimeout(promise, options) {
|
||||||
|
const {
|
||||||
|
milliseconds,
|
||||||
|
fallback,
|
||||||
|
message,
|
||||||
|
customTimers = {setTimeout, clearTimeout},
|
||||||
|
} = options;
|
||||||
|
|
||||||
let timer;
|
let timer;
|
||||||
|
|
||||||
const cancelablePromise = new Promise((resolve, reject) => {
|
const cancelablePromise = new Promise((resolve, reject) => {
|
||||||
const {milliseconds, fallback, message} = options;
|
|
||||||
|
|
||||||
if (typeof milliseconds !== 'number' || Math.sign(milliseconds) !== 1) {
|
if (typeof milliseconds !== 'number' || Math.sign(milliseconds) !== 1) {
|
||||||
throw new TypeError(`Expected \`milliseconds\` to be a positive number, got \`${milliseconds}\``);
|
throw new TypeError(`Expected \`milliseconds\` to be a positive number, got \`${milliseconds}\``);
|
||||||
}
|
}
|
||||||
|
@ -50,11 +55,6 @@ export default function pTimeout(promise, options) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
options = {
|
|
||||||
customTimers: {setTimeout, clearTimeout},
|
|
||||||
...options
|
|
||||||
};
|
|
||||||
|
|
||||||
if (options.signal) {
|
if (options.signal) {
|
||||||
const {signal} = options;
|
const {signal} = options;
|
||||||
if (signal.aborted) {
|
if (signal.aborted) {
|
||||||
|
@ -66,7 +66,7 @@ export default function pTimeout(promise, options) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
timer = options.customTimers.setTimeout.call(undefined, () => {
|
timer = customTimers.setTimeout.call(undefined, () => {
|
||||||
if (fallback) {
|
if (fallback) {
|
||||||
try {
|
try {
|
||||||
resolve(fallback());
|
resolve(fallback());
|
||||||
|
@ -93,13 +93,13 @@ export default function pTimeout(promise, options) {
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
reject(error);
|
reject(error);
|
||||||
} finally {
|
} finally {
|
||||||
options.customTimers.clearTimeout.call(undefined, timer);
|
customTimers.clearTimeout.call(undefined, timer);
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
});
|
});
|
||||||
|
|
||||||
cancelablePromise.clear = () => {
|
cancelablePromise.clear = () => {
|
||||||
clearTimeout(timer);
|
customTimers.clearTimeout.call(undefined, timer);
|
||||||
timer = undefined;
|
timer = undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -10,13 +10,15 @@ const delayedPromise: () => Promise<string> = async () => new Promise(resolve =>
|
||||||
|
|
||||||
pTimeout(delayedPromise(), {milliseconds: 50}).then(() => 'foo');
|
pTimeout(delayedPromise(), {milliseconds: 50}).then(() => 'foo');
|
||||||
pTimeout(delayedPromise(), {milliseconds: 50, fallback: async () => pTimeout(delayedPromise(), {milliseconds: 300})});
|
pTimeout(delayedPromise(), {milliseconds: 50, fallback: async () => pTimeout(delayedPromise(), {milliseconds: 300})});
|
||||||
pTimeout(delayedPromise(), {milliseconds: 50}).then(value => expectType<string>(value));
|
pTimeout(delayedPromise(), {milliseconds: 50}).then(value => {
|
||||||
pTimeout(delayedPromise(), {milliseconds: 50, message: 'error'}).then(value =>
|
expectType<string>(value);
|
||||||
expectType<string>(value)
|
});
|
||||||
);
|
pTimeout(delayedPromise(), {milliseconds: 50, message: 'error'}).then(value => {
|
||||||
pTimeout(delayedPromise(), {milliseconds: 50, message: new Error('error')}).then(value =>
|
expectType<string>(value);
|
||||||
expectType<string>(value)
|
});
|
||||||
);
|
pTimeout(delayedPromise(), {milliseconds: 50, message: new Error('error')}).then(value => {
|
||||||
|
expectType<string>(value);
|
||||||
|
});
|
||||||
pTimeout(delayedPromise(), {milliseconds: 50, fallback: async () => 10}).then(value => {
|
pTimeout(delayedPromise(), {milliseconds: 50, fallback: async () => 10}).then(value => {
|
||||||
expectType<string | number>(value);
|
expectType<string | number>(value);
|
||||||
});
|
});
|
||||||
|
@ -34,8 +36,8 @@ expectError(pTimeout(delayedPromise(), {
|
||||||
milliseconds: 50,
|
milliseconds: 50,
|
||||||
fallback: () => 10,
|
fallback: () => 10,
|
||||||
customTimers: {
|
customTimers: {
|
||||||
setTimeout
|
setTimeout,
|
||||||
}
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
expectError(pTimeout(delayedPromise(), {
|
expectError(pTimeout(delayedPromise(), {
|
||||||
|
@ -43,8 +45,8 @@ expectError(pTimeout(delayedPromise(), {
|
||||||
fallback: () => 10,
|
fallback: () => 10,
|
||||||
customTimers: {
|
customTimers: {
|
||||||
setTimeout: () => 42, // Invalid `setTimeout` implementation
|
setTimeout: () => 42, // Invalid `setTimeout` implementation
|
||||||
clearTimeout
|
clearTimeout,
|
||||||
}
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
expectError(pTimeout(delayedPromise(), {})); // `milliseconds` is required
|
expectError(pTimeout(delayedPromise(), {})); // `milliseconds` is required
|
||||||
|
|
13
package.json
13
package.json
|
@ -12,8 +12,9 @@
|
||||||
},
|
},
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"exports": "./index.js",
|
"exports": "./index.js",
|
||||||
|
"types": "./index.d.ts",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=14.16"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "xo && ava && tsd"
|
"test": "xo && ava && tsd"
|
||||||
|
@ -36,12 +37,12 @@
|
||||||
"bluebird"
|
"bluebird"
|
||||||
],
|
],
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"ava": "^3.15.0",
|
"ava": "^4.3.1",
|
||||||
"delay": "^5.0.0",
|
"delay": "^5.0.0",
|
||||||
"in-range": "^3.0.0",
|
"in-range": "^3.0.0",
|
||||||
"p-cancelable": "^2.1.0",
|
"p-cancelable": "^4.0.1",
|
||||||
"time-span": "^4.0.0",
|
"time-span": "^5.1.0",
|
||||||
"tsd": "^0.14.0",
|
"tsd": "^0.22.0",
|
||||||
"xo": "^0.38.2"
|
"xo": "^0.51.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
10
readme.md
10
readme.md
|
@ -4,14 +4,14 @@
|
||||||
|
|
||||||
## Install
|
## Install
|
||||||
|
|
||||||
```
|
```sh
|
||||||
$ npm install p-timeout
|
npm install p-timeout
|
||||||
```
|
```
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
```js
|
```js
|
||||||
import {setTimeout} from 'timers/promises';
|
import {setTimeout} from 'node:timers/promises';
|
||||||
import pTimeout from 'p-timeout';
|
import pTimeout from 'p-timeout';
|
||||||
|
|
||||||
const delayedPromise = setTimeout(200);
|
const delayedPromise = setTimeout(200);
|
||||||
|
@ -66,7 +66,7 @@ Do something other than rejecting with an error on timeout.
|
||||||
You could for example retry:
|
You could for example retry:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
import {setTimeout} from 'timers/promises';
|
import {setTimeout} from 'node:timers/promises';
|
||||||
import pTimeout from 'p-timeout';
|
import pTimeout from 'p-timeout';
|
||||||
|
|
||||||
const delayedPromise = () => setTimeout(200);
|
const delayedPromise = () => setTimeout(200);
|
||||||
|
@ -90,7 +90,7 @@ Useful for testing purposes, in particular to work around [`sinon.useFakeTimers(
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
import {setTimeout} from 'timers/promises';
|
import {setTimeout} from 'node:timers/promises';
|
||||||
import pTimeout from 'p-timeout';
|
import pTimeout from 'p-timeout';
|
||||||
|
|
||||||
const originalSetTimeout = setTimeout;
|
const originalSetTimeout = setTimeout;
|
||||||
|
|
14
test.js
14
test.js
|
@ -27,7 +27,7 @@ test('throws when milliseconds is NaN', async t => {
|
||||||
test('handles milliseconds being `Infinity`', async t => {
|
test('handles milliseconds being `Infinity`', async t => {
|
||||||
t.is(
|
t.is(
|
||||||
await pTimeout(delay(50, {value: fixture}), {milliseconds: Number.POSITIVE_INFINITY}),
|
await pTimeout(delay(50, {value: fixture}), {milliseconds: Number.POSITIVE_INFINITY}),
|
||||||
fixture
|
fixture,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -77,8 +77,8 @@ test('accepts `customTimers` option', async t => {
|
||||||
clearTimeout(timeoutId) {
|
clearTimeout(timeoutId) {
|
||||||
t.pass();
|
t.pass();
|
||||||
return clearTimeout(timeoutId);
|
return clearTimeout(timeoutId);
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -101,13 +101,13 @@ if (globalThis.AbortController !== undefined) {
|
||||||
|
|
||||||
const promise = pTimeout(delay(3000), {
|
const promise = pTimeout(delay(3000), {
|
||||||
milliseconds: 2000,
|
milliseconds: 2000,
|
||||||
signal: abortController.signal
|
signal: abortController.signal,
|
||||||
});
|
});
|
||||||
|
|
||||||
abortController.abort();
|
abortController.abort();
|
||||||
|
|
||||||
await t.throwsAsync(promise, {
|
await t.throwsAsync(promise, {
|
||||||
name: 'AbortError'
|
name: 'AbortError',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -118,9 +118,9 @@ if (globalThis.AbortController !== undefined) {
|
||||||
|
|
||||||
await t.throwsAsync(pTimeout(delay(3000), {
|
await t.throwsAsync(pTimeout(delay(3000), {
|
||||||
milliseconds: 2000,
|
milliseconds: 2000,
|
||||||
signal: abortController.signal
|
signal: abortController.signal,
|
||||||
}), {
|
}), {
|
||||||
name: 'AbortError'
|
name: 'AbortError',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue