Security News
Bun 1.2 Released with 90% Node.js Compatibility and Built-in S3 Object Support
Bun 1.2 enhances its JavaScript runtime with 90% Node.js compatibility, built-in S3 and Postgres support, HTML Imports, and faster, cloud-first performance.
always-done
Advanced tools
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
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
Install with npm
$ npm i always-done --save
For more use-cases see the tests
const fs = require('fs')
const alwaysDone = require('always-done')
alwaysDone((cb) => {
fs.readFile('./package.json', 'utf8', cb)
}, (err, res) => {
if (err) return console.error(err)
let json = JSON.parse(res)
console.log(json.name) // => 'always-done'
})
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 is 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.
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.
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[opts]
{Object}: optional options, such as context
and args
, passed to try-catch-core[opts.context]
{Object}: context to be passed to fn
[opts.args]
{Array}: custom argument(s) to be pass to fn
, given value is arrayified[opts.passCallback]
{Boolean}: pass true
if you want cb
to be passed to fn
args[done]
{Function}: on completionreturns
{Function}: thunk until you pass done
to that thunkExample
var alwaysDone = require('always-done')
var options = {
context: { num: 123, bool: true }
args: [require('assert')]
}
alwaysDone(function (assert, next) {
assert.strictEqual(this.num, 123)
assert.strictEqual(this.bool, true)
next()
}, options, function (err) {
console.log(err, 'done') // => null, 'done'
})
alwaysDone(function (cb) {
cb(new Error('foo bar'))
}, function done (err) {
console.log(err) // => Error: foo bar
})
Handles completion and errors of async/await, synchronous and asynchronous (callback) functions, also functions that returns streams, promises, child process and observables.
async/await
completionalwaysDone(async function () {
return await Promise.resolve('foobar')
}, function done (e, res) {
console.log(res) // => 'foobar'
})
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'
})
alwaysDone(function () {
return 123
}, function done (e, res) {
console.log(res) // => 123
})
alwaysDone(function () {
return new Error('qux bar')
}, function done (err) {
console.log(err.message) // => 'qux bar'
})
alwaysDone(function () {
return Promise.resolve(12345)
}, function done (e, res) {
console.log(res) // => 12345
})
alwaysDone(function () {
return Promise.reject(new Error('foo bar'))
}, function done (err) {
console.log(err.message) // => 'foo bar
})
Using on-stream-end and stream-exhaust
alwaysDone(function () {
return fs.createReadStream('./package.json')
}, function done (e) {
console.log('stream completed')
})
alwaysDone(function () {
return fs.createReadStream('foo bar')
}, function done (err) {
console.log(err.code) // => ENOENT
console.log(err.message) // => No such file or directory
})
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
})
Using
.subscribe
method of the observable
var Observable = require('rx').Observable
alwaysDone(function () {
return Observable.empty()
}, function done (e, res) {
console.log(e, res) // => null, undefined
})
alwaysDone(function () {
return Observable.return([1, 2, 3])
}, function done (e, res) {
console.log(res) // => [1, 2, 3]
})
alwaysDone(function () {
return Observable.throw(new Error('observable error'))
}, function done (err) {
console.log(err.message) // => 'observable error'
})
Basically, they are streams, so completion is handled using on-stream-end which is drop-in replacement for end-of-stream
var cp = require('child_process')
alwaysDone(function () {
return cp.exec('echo hello world')
}, function done (e, res) {
console.log(res) // => 'hello world'
})
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'
})
var cp = require('child_process')
alwaysDone(function () {
return cp.spawn('foo-bar-baz', ['hello world'])
}, function done (err) {
console.log(err.code) // => ENOENT
})
alwaysDone(function () {
foo // ReferenceError
return 55
}, function (err) {
console.log(err.name)
// => ReferenceError: foo is not defined
})
alwaysDone(function () {
JSON.parse('{"foo":')
}, function (err) {
console.log(err)
// => SyntaxError: Unexpected end of JSON input
})
It may looks strange, but it's logical. If you pass empty function it just completes with
undefined
result andnull
error.
Example
// passing empty function
alwaysDone(function () {}, function (err, res) {
console.log(err, res) // => null, undefined
})
var alwaysDone = require('always-done')
var opts = {
context: { foo: 'bar' }
}
alwaysDone(function () {
console.log(this.foo) // => 'bar'
}, opts, function done () {
console.log('end')
})
It may be strange, but this allows you to pass more arguments to that first function and the last argument always will be "callback" until
fn
is async or sync but withpassCallback: true
option.
var alwaysDone = require('always-done')
var options = {
args: [1, 2]
}
alwaysDone(function (a, b) {
console.log(arguments.length) // => 2
console.log(a) // => 1
console.log(b) // => 2
return a + b + 3
}, options, function done (e, res) {
console.log(res) // => 9
})
Can be used as thunkify lib without problems, just don't pass a done callback.
var fs = require('fs')
var alwaysDone = require('always-done')
var readFileThunk = alwaysDone(function (cb) {
fs.readFile('./package.json', cb)
})
readFileThunk(function done (err, res) {
console.log(err, res) // => null, Buffer
})
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.
FAQs
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
The npm package always-done receives a total of 29 weekly downloads. As such, always-done popularity was classified as not popular.
We found that always-done demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Bun 1.2 enhances its JavaScript runtime with 90% Node.js compatibility, built-in S3 and Postgres support, HTML Imports, and faster, cloud-first performance.
Security News
Biden's executive order pushes for AI-driven cybersecurity, software supply chain transparency, and stronger protections for federal and open source systems.
Security News
Fluent Assertions is facing backlash after dropping the Apache license for a commercial model, leaving users blindsided and questioning contributor rights.