Package Exports
- always-done
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (always-done) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
always-done

Handle completion and errors with elegance! Support for streams, callbacks, promises, child processes, async/await and sync functions. A drop-in replacement for async-done - pass 100% of its tests plus more
Table of Contents
Install
Install with npm
$ npm i always-done --save
Usage
For more use-cases see the tests
const alwaysDone = require('always-done')
API
alwaysDone
Handle completion of
fn
and optionally passdone
callback, otherwise it returns a thunk. If thatthunk
does not accept function, it returns another thunk until you passdone
to it.
Params
<fn>
{Function}: function to be called[done]
{Function}: on completionreturns
{Function}: thunk until you passdone
to that thunk
Example
var alwaysDone = require('always-done')
alwaysDone(function (cb) {
cb(null, 123)
}, function done (err, res) {
console.log(err, res) // => null, 123
})
alwaysDone(function (cb) {
cb(new Error('foo bar'))
}, function done (err) {
console.log(err) // => Error: foo bar
})
Background
Behind the scenes we use just good plain old try/catch
block. Sounds you strange? See what "hard" job is done on try-catch-callback and try-catch-core.
In the first one, we just calls a function inside try/catch and calls done
callback with error or result of that function.
About second one, there we wraps the done
callback with once and dezalgo to ensure it will be called in the next tick.
Here, in always-done
, we just give a callback
to that try-catch-core package and "listen" what are the result. Actually we not listening anything, we just make a few checks to understand what the incoming value is - promise, child process, stream, observable and etc.
Resolution
Nothing so magical. Try/catch block for most of the things works briliant. And on-stream-end module (which is drop-in replacement for end-of-stream) for streams and child processes.
Support
async/await completion
alwaysDone(async function () {
return await Promise.resolve('foobar')
}, function done (e, res) {
console.log(res) // => 'foobar'
})
Callbacks completion
var alwaysDone = require('always-done')
alwaysDone(function (cb) {
fs.readFile('./package.json', 'utf8', cb)
}, function done (err, res) {
if (err) return console.log(err)
var pkg = JSON.parse(res)
console.log(pkg.name) // => 'always-done'
})
Synchronous functions
Returning a value
alwaysDone(function () {
return 123
}, function done (e, res) {
console.log(res) // => 123
})
Returning an error
alwaysDone(function () {
return new Error('qux bar')
}, function done (err) {
console.log(err.message) // => 'qux bar'
})
Promises
Returning a resolved Promise
alwaysDone(function () {
return Promise.resolve(12345)
}, function done (e, res) {
console.log(res) // => 12345
})
Returning a rejected Promise
alwaysDone(function () {
return Promise.reject(new Error('foo bar'))
}, function done (err) {
console.log(err.message) // => 'foo bar
})
Streams
Unpiped streams
alwaysDone(function () {
return fs.createReadStream('./package.json')
}, function done (e) {
console.log('stream completed')
})
Failing unpiped streams
alwaysDone(function () {
return fs.createReadStream('foo bar')
}, function done (err) {
console.log(err.code) // => ENOENT
console.log(err.message) // => No such file or directory
})
Failing piped streams
alwaysDone(function () {
var read = fs.createReadStream('foo bar')
return read.pipe(through2())
}, function done (err) {
console.log(err.code) // => ENOENT
console.log(err.message) // => No such file or directory
})
Observables
Empty observable
var Observable = require('rx').Observable
alwaysDone(function () {
return Observable.empty()
}, function done (e, res) {
console.log(e, res) // => null, undefined
})
Successful observable
alwaysDone(function () {
return Observable.return([1, 2, 3])
}, function done (e, res) {
console.log(res) // => [1, 2, 3]
})
Failing observable
alwaysDone(function () {
return Observable.throw(new Error('observable error'))
}, function done (err) {
console.log(err.message) // => 'observable error'
})
Child Process
Successful exec
var cp = require('child_process')
alwaysDone(function () {
return cp.exec('echo hello world')
}, function done (e, res) {
console.log(res) // => 'hello world'
})
Failing exec
var cp = require('child_process')
alwaysDone(function () {
return cp.exec('foo-bar-baz sasa')
}, function done (err) {
console.log(err.message) // => 'exited with error code: 12'
})
Failing spawn
var cp = require('child_process')
alwaysDone(function () {
return cp.spawn('foo-bar-baz', ['hello world'])
}, function done (err) {
console.log(err.code) // => ENOENT
})
Handling native errors
alwaysDone(function () {
foo
return 55
}, function (err) {
console.log(err.name)
// => ReferenceError: foo is not defined
})
Always completes
It may looks strange, but it's logical.
Example
// passing empty function
alwaysDone(function () {}, function (err, res) {
console.log(err, res) // => null, undefined
})
Related
- async-done: Force async using nextTick and normalize completion/errors for callbacks, promises, observables, child… more | homepage
- base: base is the foundation for creating modular, unit testable and highly pluggable… more | homepage
- end-of-stream: Call a callback when a readable/writable/duplex stream has completed or failed. | homepage
- is-node-stream: Strictly and correctly checks if value is a nodejs stream. | homepage
- minibase: MiniBase is minimalist approach to Base - @node-base, the awesome framework. Foundation… more | homepage
- on-stream-end: Handles completion and errors of any stream - readable/writable/duplex. | homepage
- try-catch-callback: try/catch block with a callback, used in try-catch-core. Use it when you… more | homepage
- try-catch-core: Asynchronous and sync tryCatch in one place. The callback is securely wrapped… more | homepage
Contributing
Pull requests and stars are always welcome. For bugs and feature requests, please create an issue.
But before doing anything, please read the CONTRIBUTING.md guidelines.