Require Node.js 8, add TypeScript definition (#10)
This commit is contained in:
parent
db65c4b511
commit
9a429bc248
|
@ -1,2 +1 @@
|
|||
* text=auto
|
||||
*.js text eol=lf
|
||||
* text=auto eol=lf
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
language: node_js
|
||||
node_js:
|
||||
- '10'
|
||||
- '8'
|
||||
- '6'
|
||||
- '4'
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
/**
|
||||
* Timeout a promise after a specified amount of time.
|
||||
*
|
||||
* If you pass in a cancelable promise, specifically a promise with a `.cancel()` method, that method will be called when the `pTimeout` promise times out.
|
||||
*
|
||||
* @param input - Promise to decorate.
|
||||
* @param ms - Milliseconds before timing out.
|
||||
* @param message - Specify a custom error message or error. If you do a custom error, it's recommended to sub-class `pTimeout.TimeoutError`. Default: `'Promise timed out after 50 milliseconds'`.
|
||||
* @returns A decorated `input` that times out after `ms` time.
|
||||
*/
|
||||
export default function pTimeout<ValueType>(
|
||||
input: PromiseLike<ValueType>,
|
||||
ms: number,
|
||||
message?: string | Error
|
||||
): Promise<ValueType>;
|
||||
|
||||
/**
|
||||
* Timeout a promise after a specified amount of time.
|
||||
*
|
||||
* If you pass in a cancelable promise, specifically a promise with a `.cancel()` method, that method will be called when the `pTimeout` promise times out.
|
||||
*
|
||||
* @param input - Promise to decorate.
|
||||
* @param ms - Milliseconds before timing out.
|
||||
* @param fallback - Do something other than rejecting with an error on timeout. You could for example retry.
|
||||
* @returns A decorated `input` that times out after `ms` time.
|
||||
*
|
||||
* @example
|
||||
*
|
||||
* import delay from 'delay';
|
||||
* import pTimeout from 'p-timeout';
|
||||
*
|
||||
* const delayedPromise = () => delay(200);
|
||||
*
|
||||
* pTimeout(delayedPromise(), 50, () => {
|
||||
* return pTimeout(delayedPromise(), 300);
|
||||
* });
|
||||
*/
|
||||
export default function pTimeout<ValueType, ReturnType>(
|
||||
input: PromiseLike<ValueType>,
|
||||
ms: number,
|
||||
fallback: () => ReturnType | Promise<ReturnType>
|
||||
): Promise<ValueType | ReturnType>;
|
||||
|
||||
export class TimeoutError extends Error {
|
||||
readonly name: 'TimeoutError';
|
||||
constructor(message?: string);
|
||||
}
|
16
index.js
16
index.js
|
@ -1,4 +1,5 @@
|
|||
'use strict';
|
||||
|
||||
const pFinally = require('p-finally');
|
||||
|
||||
class TimeoutError extends Error {
|
||||
|
@ -8,7 +9,7 @@ class TimeoutError extends Error {
|
|||
}
|
||||
}
|
||||
|
||||
module.exports = (promise, ms, fallback) => new Promise((resolve, reject) => {
|
||||
const pTimeout = (promise, ms, fallback) => new Promise((resolve, reject) => {
|
||||
if (typeof ms !== 'number' || ms < 0) {
|
||||
throw new TypeError('Expected `ms` to be a positive number');
|
||||
}
|
||||
|
@ -17,23 +18,25 @@ module.exports = (promise, ms, fallback) => new Promise((resolve, reject) => {
|
|||
if (typeof fallback === 'function') {
|
||||
try {
|
||||
resolve(fallback());
|
||||
} catch (err) {
|
||||
reject(err);
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const message = typeof fallback === 'string' ? fallback : `Promise timed out after ${ms} milliseconds`;
|
||||
const err = fallback instanceof Error ? fallback : new TimeoutError(message);
|
||||
const timeoutError = fallback instanceof Error ? fallback : new TimeoutError(message);
|
||||
|
||||
if (typeof promise.cancel === 'function') {
|
||||
promise.cancel();
|
||||
}
|
||||
|
||||
reject(err);
|
||||
reject(timeoutError);
|
||||
}, ms);
|
||||
|
||||
pFinally(
|
||||
// eslint-disable-next-line promise/prefer-await-to-then
|
||||
promise.then(resolve, reject),
|
||||
() => {
|
||||
clearTimeout(timer);
|
||||
|
@ -41,4 +44,7 @@ module.exports = (promise, ms, fallback) => new Promise((resolve, reject) => {
|
|||
);
|
||||
});
|
||||
|
||||
module.exports = pTimeout;
|
||||
module.exports.default = pTimeout;
|
||||
|
||||
module.exports.TimeoutError = TimeoutError;
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
import {expectType} from 'tsd-check';
|
||||
import pTimeout, {TimeoutError} from '.';
|
||||
|
||||
const delayedPromise: () => Promise<string> = () =>
|
||||
new Promise(resolve => setTimeout(() => resolve('foo'), 200));
|
||||
|
||||
pTimeout(delayedPromise(), 50).then(() => 'foo');
|
||||
pTimeout(delayedPromise(), 50, () => {
|
||||
return pTimeout(delayedPromise(), 300);
|
||||
});
|
||||
pTimeout(delayedPromise(), 50).then(value => expectType<string>(value));
|
||||
pTimeout(delayedPromise(), 50, 'error').then(value =>
|
||||
expectType<string>(value)
|
||||
);
|
||||
pTimeout(delayedPromise(), 50, new Error('error')).then(value =>
|
||||
expectType<string>(value)
|
||||
);
|
||||
pTimeout(delayedPromise(), 50, async () => 10).then(value => {
|
||||
expectType<string | number>(value);
|
||||
});
|
||||
pTimeout(delayedPromise(), 50, () => 10).then(value => {
|
||||
expectType<string | number>(value);
|
||||
});
|
||||
|
||||
expectType<typeof TimeoutError>(TimeoutError);
|
16
package.json
16
package.json
|
@ -10,13 +10,14 @@
|
|||
"url": "sindresorhus.com"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
"node": ">=8"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "xo && ava"
|
||||
"test": "xo && ava && tsd-check"
|
||||
},
|
||||
"files": [
|
||||
"index.js"
|
||||
"index.js",
|
||||
"index.d.ts"
|
||||
],
|
||||
"keywords": [
|
||||
"promise",
|
||||
|
@ -35,9 +36,10 @@
|
|||
"p-finally": "^1.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"ava": "*",
|
||||
"delay": "^2.0.0",
|
||||
"p-cancelable": "^0.3.0",
|
||||
"xo": "*"
|
||||
"ava": "^1.3.1",
|
||||
"delay": "^4.1.0",
|
||||
"p-cancelable": "^1.1.0",
|
||||
"tsd-check": "^0.3.0",
|
||||
"xo": "^0.24.0"
|
||||
}
|
||||
}
|
||||
|
|
29
test.js
29
test.js
|
@ -1,49 +1,50 @@
|
|||
import test from 'ava';
|
||||
import delay from 'delay';
|
||||
import PCancelable from 'p-cancelable';
|
||||
import m from '.';
|
||||
import pTimeout from '.';
|
||||
|
||||
const fixture = Symbol('fixture');
|
||||
const fixtureErr = new Error('fixture');
|
||||
|
||||
test('resolves before timeout', async t => {
|
||||
t.is(await m(delay(50).then(() => fixture), 200), fixture);
|
||||
t.is(await pTimeout(delay(50).then(() => fixture), 200), fixture);
|
||||
});
|
||||
|
||||
test('throws when ms is not number', async t => {
|
||||
await t.throws(m(delay(50), '200'), TypeError);
|
||||
await t.throwsAsync(pTimeout(delay(50), '200'), TypeError);
|
||||
});
|
||||
|
||||
test('throws when ms is negative number', async t => {
|
||||
await t.throws(m(delay(50), -1), TypeError);
|
||||
await t.throwsAsync(pTimeout(delay(50), -1), TypeError);
|
||||
});
|
||||
|
||||
test('rejects after timeout', async t => {
|
||||
await t.throws(m(delay(200), 50), m.TimeoutError);
|
||||
await t.throwsAsync(pTimeout(delay(200), 50), pTimeout.TimeoutError);
|
||||
});
|
||||
|
||||
test('rejects before timeout if specified promise rejects', async t => {
|
||||
await t.throws(m(delay(50).then(() => Promise.reject(fixtureErr)), 200), fixtureErr.message);
|
||||
await t.throwsAsync(pTimeout(delay(50).then(() => Promise.reject(fixtureErr)), 200), fixtureErr.message);
|
||||
});
|
||||
|
||||
test('fallback argument', async t => {
|
||||
await t.throws(m(delay(200), 50, 'rainbow'), 'rainbow');
|
||||
await t.throws(m(delay(200), 50, new RangeError('cake')), RangeError);
|
||||
await t.throws(m(delay(200), 50, () => Promise.reject(fixtureErr)), fixtureErr.message);
|
||||
await t.throws(m(delay(200), 50, () => {
|
||||
await t.throwsAsync(pTimeout(delay(200), 50, 'rainbow'), 'rainbow');
|
||||
await t.throwsAsync(pTimeout(delay(200), 50, new RangeError('cake')), RangeError);
|
||||
await t.throwsAsync(pTimeout(delay(200), 50, () => Promise.reject(fixtureErr)), fixtureErr.message);
|
||||
await t.throwsAsync(pTimeout(delay(200), 50, () => {
|
||||
throw new RangeError('cake');
|
||||
}), RangeError);
|
||||
});
|
||||
|
||||
test('calls `.cancel()` on promise when it exists', async t => {
|
||||
const p = new PCancelable(onCancel => {
|
||||
const promise = new PCancelable(async (resolve, reject, onCancel) => {
|
||||
onCancel(() => {
|
||||
t.pass();
|
||||
});
|
||||
|
||||
return delay(200);
|
||||
await delay(200);
|
||||
resolve();
|
||||
});
|
||||
|
||||
await t.throws(m(p, 50), m.TimeoutError);
|
||||
t.true(p.canceled);
|
||||
await t.throwsAsync(pTimeout(promise, 50), pTimeout.TimeoutError);
|
||||
t.true(promise.isCanceled);
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue