npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

always-done

v1.1.0

Published

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

Downloads

213

Readme

always-done npmjs.com The MIT License npm downloads

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

code climate standard code style travis build status coverage status dependency status

Table of Contents

Install

Install with npm

$ npm i always-done --save

Usage

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'
})

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 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.

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.

back to top

API

alwaysDone

Handle completion of fn and optionally pass done callback, otherwise it returns a thunk. If that thunk does not accept function, it returns another thunk until you pass done 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 completion
  • returns {Function}: thunk until you pass done to that thunk

Example

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
})

back to top

Supports

Handles completion and errors of async/await, synchronous and asynchronous (callback) functions, also functions that returns streams, promises, child process and observables.

Handles async/await completion

alwaysDone(async function () {
  return await Promise.resolve('foobar')
}, function done (e, res) {
  console.log(res) // => 'foobar'
})

back to top

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'
})

back to top

Completion of 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'
})

back to top

Completion of 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
})

back to top

Streams completion

Using on-stream-end and stream-exhaust

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
})

back to top

Handles completion of Observables

Using .subscribe method of the observable

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'
})

back to top

Completion of Child Process

Basically, they are streams, so completion is handled using on-stream-end which is drop-in replacement for end-of-stream

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
})

back to top

Handling errors

uncaught exceptions

alwaysDone(function () {
  foo // ReferenceError
  return 55
}, function (err) {
  console.log(err.name)
  // => ReferenceError: foo is not defined
})

thrown errors

alwaysDone(function () {
  JSON.parse('{"foo":')
}, function (err) {
  console.log(err)
  // => SyntaxError: Unexpected end of JSON input
})

back to top

Always completes

It may looks strange, but it's logical. If you pass empty function it just completes with undefined result and null error.

Example

// passing empty function
alwaysDone(function () {}, function (err, res) {
  console.log(err, res) // => null, undefined
})

back to top

Passing custom context

var alwaysDone = require('always-done')
var opts = {
  context: { foo: 'bar' }
}

alwaysDone(function () {
  console.log(this.foo) // => 'bar'
}, opts, function done () {
  console.log('end')
})

back to top

Passing custom arguments

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 with passCallback: 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
})

back to top

Returning a thunk

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
})

back to top

Related

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.

Charlike Make Reagent new message to charlike freenode #charlike

tunnckoCore.tk keybase tunnckoCore tunnckoCore npm tunnckoCore twitter tunnckoCore github