Introduction
TS-Promise is a fast, robust, type-safe promise library.
Features:
- Promises/A+ 1.1 compliant
- ES6 Promise interface compatible
- Long stack traces support (switchable at runtime!)
- Fast
- Efficiently supports infinite recursion (with and without long stack traces)
- Early throwing of unhandled rejections with
.done()
- No progression handlers
- Optional explicit promise chain flushing, useful for test frameworks
- Readable code (not too many tricks)
For other planned features, see the TODO below.
Usage example
Install using npm
:
cd your-project
npm install --save ts-promise
If you use TypeScript, use "moduleResolution": "node"
in your tsconfig.json
to let it automatically pick up the typings of this package.
import Promise from "ts-promise";
Promise.resolve("hello world").then((v) => {
console.log(v);
});
Promise.setLongTraces(true);
var p = Promise.resolve();
p.then(() => {
return Promise.reject(new Error("my error"));
}).catch((e) => {
console.error(e.stack);
});
Example output of the above:
"hello world"
Error: my error
at /home/martin/src/promise-example/example.js:9:35
at Promise._unwrap (/home/martin/src/ts-promise/src/lib/Promise.ts:542:20)
at Promise._unwrapper (/home/martin/src/ts-promise/src/lib/Promise.ts:557:19)
at CallQueue.flush (/home/martin/src/ts-promise/src/lib/async.ts:47:4)
at Async.flush (/home/martin/src/ts-promise/src/lib/async.ts:116:19)
at Async._scheduledFlush (/home/martin/src/ts-promise/src/lib/async.ts:95:9)
at Object.Async._flusher [as _onImmediate] (/home/martin/src/ts-promise/src/lib/async.ts:58:50)
at processImmediate [as _immediateCallback] (timers.js:330:15)
from Promise at:
at Function.Promise.reject (/home/martin/src/ts-promise/src/lib/Promise.ts:211:11)
at /home/martin/src/promise-example/example.js:9:28
at Promise._unwrap (/home/martin/src/ts-promise/src/lib/Promise.ts:542:20)
at Promise._unwrapper (/home/martin/src/ts-promise/src/lib/Promise.ts:557:19)
at CallQueue.flush (/home/martin/src/ts-promise/src/lib/async.ts:47:4)
at Async.flush (/home/martin/src/ts-promise/src/lib/async.ts:116:19)
at Async._scheduledFlush (/home/martin/src/ts-promise/src/lib/async.ts:95:9)
at Object.Async._flusher [as _onImmediate] (/home/martin/src/ts-promise/src/lib/async.ts:58:50)
at processImmediate [as _immediateCallback] (timers.js:330:15)
from previous:
at Promise.then (/home/martin/src/ts-promise/src/lib/Promise.ts:181:15)
at Object.<anonymous> (/home/martin/src/promise-example/example.js:8:3)
at Module._compile (module.js:456:26)
at Object.Module._extensions..js (module.js:474:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)
at Function.Module.runMain (module.js:497:10)
at startup (node.js:119:16)
at node.js:902:3
from previous:
at Function.Promise.resolve (/home/martin/src/ts-promise/src/lib/Promise.ts:205:11)
at Object.<anonymous> (/home/martin/src/promise-example/example.js:7:25)
at Module._compile (module.js:456:26)
at Object.Module._extensions..js (module.js:474:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)
at Function.Module.runMain (module.js:497:10)
at startup (node.js:119:16)
at node.js:902:3
Docs
All public methods and interfaces have JSDoc comments, so if your favorite IDE
supports these, you'll have instant inline documentation.
That said, the library's interface should be very unsurprising: basically ES6
Promises with some extras.
For your convenience, here's a list of what's available on Promise.
Static methods on Promise:
Methods on Promise instances:
then<R>(onFulfilled?: (value: T) => R | Thenable<R>, onRejected?: (reason: Error) => R | Thenable<R>): Promise<R>
See ES6 Promise speccatch<R>(onRejected?: (reason: Error) => R | Thenable<R>): Promise<R>
See ES6 Promise specdone<R>(onFulfilled?: (value: T) => void | Thenable<void>, onRejected?: (reason: Error) => void | Thenable<void>): void
done()
behaves like .then()
but does not return a new promise. Instead,
it throws an UnhandledRejectionError
when the final result of the promise
chain is a rejected Promise (.reason
property of the error).
Note that it is technically safe to 'continue' the program after e.g. catching
the error through Node's uncaughtException
, or when running in a browser.finally(handler: (result: Promise<T>) => void|Thenable<void>): Promise<T>
Asynchronous equivalent of try { } finally { }.
Runs handler
when promise resolves (fulfilled or rejected).
Handler is passed the current promise (which is guaranteed to be
resolved), and can be interrogated with e.g. isFulfilled()
, .value()
,
etc.
When handler
returns undefined
or its promise is fulfilled, the
promise from finally()
is resolved to the original promise's resolved
value or rejection reason.
If handler
throws an error or returns a rejection, the result of
finally()
will be rejected with that error.
Example:
someLenghtyOperation().finally((result) => {
if (result.isFulfilled()) {
console.log("succeeded");
} else {
console.log("failed", result.reason());
}
});isFulfilled(): boolean
Returns true when promise is fulfilled, false otherwise.isRejected(): boolean
Returns true when promise is rejected, false otherwise.isPending(): boolean
Returns true when promise is still pending, false otherwise.value(): T
Returns fulfillment value if fulfilled, otherwise throws an error.reason(): any
Returns rejection reason if rejected, otherwise throws an error.toString(): string
Returns a human-readable representation of the promise and its status.inspect(): string
Returns a human-readable representation of the promise and its status.delay(ms: number): Promise<T>
Create a promise that resolves with the same value of this promise, after
ms
milliseconds. The timer will start when the current promise is resolved.
If the current promise is rejected, the resulting promise is also rejected,
without waiting for the timer.
TODO
Planned features (in fairly arbitrary order):
- Auto-generate online docs using TypeDoc
- Replace/update the (slightly out-of-date) docs above
- Implement property-based catch() predicate (error constructor(s) and function
already done)
- Possibly-unhandled-rejection detection
- Non-V8-support: it works in non-V8, but long stack traces aren't available
- Switch (back) to process.nextTick() / MutationObserver etc
- Implement
.promisify()
- Simplify code somewhat more (most notably reduce duplication of 'called'-logic
when resolving, maybe also slightly simplify async callback queue
implementation)
Interesting ideas that need further investigation:
-
Support for differentiating between programmer errors (e.g. assertions, null
derefences) and 'expected' errors. E.g. bluebird has .error()
and the
concept of OperationalError, but this may not be the best way to interoperate
with other libraries.
-
Possibly-unterminated-promise-chain detection. Wild idea that could help to
always make sure to either return a promise from a function, or properly
terminate it, thus reducing the chance of a PossiblyUnhandledRejectionError at
runtime.
-
.settle()
and/or other form of simply waiting for a bunch of void-promises,
but await all of them before returning, even in case of errors. To prevent
e.g. shutting things down while some tasks were still running.
-
Split off async callback queue and stack trace handling into separate packages
to allow re-use by other packages.
-
UMD support? Submit an issue if you think this is useful to you, as I'm more
of a browserify guy myself.
Development
Found an issue? Have an idea? Wanna help? Submit an issue!
git clone https://github.com/poelstra/ts-promise
cd ts-promise
npm install
# hack hack, code code...
npm run prepublish
Changelog
0.3.0 (2016-02-26):
- Switch to
"moduleResolution": "node"
-compatible typings
-- To use these typings, simply put that setting in your tsconfig.json
and
remove the (manual) reference to the ts-promise.d.ts file from your project. - Update to latest Typescript (1.8.2)
- Update to latest TSLint, fix linting errors
async.setScheduler()
now uses undefined
(instead of null
) to reset,
but the old behaviour still works (though deprecated)
0.2.5 (2016-02-08):
- Replace previous
setImmediate
hack with non-global-polluting one (#8)
0.2.4 (2016-01-30):
- Stub
setImmediate
in case of browserify'ed environment (#8)
0.2.3 (2015-08-27):
- Fix stack overflow for very long unresolved promise chains
- Simplify and document internal unwrapping logic
0.2.2 (2015-08-04):
- Implement
.finally()
(#3) - Add
Inspection<T>
interface (#4) - Don't confuse users by showing our internal stack trace when Node didn't provide one for UnhandledRejectionError
0.2.1 (2015-06-24):
- Improve stack trace for UnhandledRejectionError
- Allow specifying Error classes with different constructor arguments in
.catch()
0.2.0 (2015-06-23):
- Allow passing predicate to
.catch()
(Error class or array of them, or a
custom matching function) - Add
.return()
and .throw()
helpers - Document all public members of Promise and UnhandledRejectionError
- Stricter typing for
Promise.reject()
, no longer returns Promise<any>
by
default - Require
.then()
and .catch()
to have first callback (for typing only,
implementation supports full Promises/A+) - Include .ts sources to not confuse debugger due to sourcemaps also being
included
- Fix building on Windows
0.1.5 (2015-05-17):
- Add Promise.race()
- Add .delay() on Promise and instance
0.1.4 (2015-05-13):
- Add longStackTraces support to .done()
- Export VoidDeferred interface and allow resolving it with a Thenable
- Add .toString() and .inspect()
0.1.3 (2015-05-09):
- Add Promise.defer()
- Add stack to BaseError
- Add rejection reason to UnhandledRejectionError
- 100% code coverage
0.1.2 (2015-05-07):
- Fix bundled .d.ts file for default export
- Add synchronous inspection API
- Export BaseError (to be moved to separate package later)
0.1.1 (2015-05-06):
- Transparent support for mocked timers (e.g. Sinon.useFakeTimers())
0.1.0 (2015-05-04):
License
The MIT license.