commit b07580fbdbae667850ef10b12d5ce2e53d99214e Author: Sindre Sorhus Date: Fri Oct 21 13:42:17 2016 +0700 init diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..98a761d --- /dev/null +++ b/.editorconfig @@ -0,0 +1,12 @@ +root = true + +[*] +indent_style = tab +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[{package.json,*.yml}] +indent_style = space +indent_size = 2 diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..391f0a4 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +* text=auto +*.js text eol=lf diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3c3629e --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..97519af --- /dev/null +++ b/.travis.yml @@ -0,0 +1,4 @@ +language: node_js +node_js: + - '6' + - '4' diff --git a/index.js b/index.js new file mode 100644 index 0000000..1abd28b --- /dev/null +++ b/index.js @@ -0,0 +1,40 @@ +'use strict'; + +class TimeoutError extends Error { + constructor(message) { + super(message); + this.name = 'TimeoutError'; + this.message = message; + } +} + +module.exports = (promise, ms, fallback) => new Promise((resolve, reject) => { + if (!Number.isFinite(ms)) { + throw new TypeError('Expected `ms` to be a finite number'); + } + + const timer = setTimeout(() => { + if (typeof fallback === 'function') { + resolve(fallback()); + return; + } + + const message = typeof fallback === 'string' ? fallback : `Promise timed out after ${ms} milliseconds`; + const err = fallback instanceof Error ? fallback : new TimeoutError(message); + + reject(err); + }, ms); + + promise.then( + val => { + clearTimeout(timer); + resolve(val); + }, + err => { + clearTimeout(timer); + reject(err); + } + ); +}); + +module.exports.TimeoutError = TimeoutError; diff --git a/license b/license new file mode 100644 index 0000000..654d0bf --- /dev/null +++ b/license @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/package.json b/package.json new file mode 100644 index 0000000..1c8262a --- /dev/null +++ b/package.json @@ -0,0 +1,42 @@ +{ + "name": "p-timeout", + "version": "0.0.0", + "description": "Timeout a promise after a specified amount of time", + "license": "MIT", + "repository": "sindresorhus/p-timeout", + "author": { + "name": "Sindre Sorhus", + "email": "sindresorhus@gmail.com", + "url": "sindresorhus.com" + }, + "engines": { + "node": ">=4" + }, + "scripts": { + "test": "xo && ava" + }, + "files": [ + "index.js" + ], + "keywords": [ + "promise", + "timeout", + "error", + "invalidate", + "async", + "await", + "promises", + "time", + "out", + "cancel", + "bluebird" + ], + "devDependencies": { + "ava": "*", + "delay": "^1.3.1", + "xo": "*" + }, + "xo": { + "esnext": true + } +} diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..4b29220 --- /dev/null +++ b/readme.md @@ -0,0 +1,86 @@ +# p-timeout [![Build Status](https://travis-ci.org/sindresorhus/p-timeout.svg?branch=master)](https://travis-ci.org/sindresorhus/p-timeout) + +> Timeout a promise after a specified amount of time + + +## Install + +``` +$ npm install --save p-timeout +``` + + +## Usage + +```js +const delay = require('delay'); +const pTimeout = require('p-timeout'); + +const delayedPromise = delay(200); + +pTimeout(delayedPromise, 50).then(() => 'foo'); +//=> [TimeoutError: Promise timed out after 50 milliseconds] +``` + + +## API + +### pTimeout(input, ms, [message | fallback]) + +Returns a decorated `input` that times out after `ms` time. + +#### input + +Type: `Promise` + +Promise to decorate. + +#### ms + +Type: `number` + +Milliseconds before timing out. + +#### message + +Type: `string` `Error`
+Default: `'Promise timed out after 50 milliseconds'` + +Specify a custom error message or error. + +If you do a custom error, it's recommended to sub-class `pTimeout.TimeoutError`. + +#### fallback + +Type: `Function` + +Do something other than rejecting with an error on timeout. + +You could for example retry: + +```js +const delay = require('delay'); +const pTimeout = require('p-timeout'); + +const delayedPromise = () => delay(200); + +pTimeout(delayedPromise(), 50, () => { + return pTimeout(delayedPromise(), 300); +}); +``` + +### pTimeout.TimeoutError + +Exposed for instance checking and sub-classing. + + +## Related + +- [delay](https://github.com/sindresorhus/delay) - Delay a promise a specified amount of time +- [p-retry](https://github.com/sindresorhus/p-retry) - Retry a promise-returning function +- [More…](https://github.com/sindresorhus/promise-fun) + + +## License + +MIT © [Sindre Sorhus](https://sindresorhus.com) diff --git a/test.js b/test.js new file mode 100644 index 0000000..435e991 --- /dev/null +++ b/test.js @@ -0,0 +1,24 @@ +import test from 'ava'; +import delay from 'delay'; +import m 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); +}); + +test('rejects after timeout', async t => { + await t.throws(m(delay(200), 50), m.TimeoutError); +}); + +test('rejects before timeout if specified promise rejects', async t => { + await t.throws(m(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); +});