1. nonsynchronous
async/await callback fusioning utilities
nonsynchronous
Package: nonsynchronous
Created by: davidmarkclements
Last modified: Wed, 11 May 2022 09:00:45 GMT
Version: 1.2.0
License: MIT
Downloads: 3,490
Repository: https://github.com/davidmarkclements/nonsynchronous

Install

npm install nonsynchronous
yarn add nonsynchronous

nonsynchronous

async/await callback fusioning utilities

Functions

Promisify

Implementation:

 const { promisify } = require('util')

The same promisify as provided in Node core.

Example:

 const { promisify } = require('nonsynchronous')
const fs = require('fs')
const stat = promisify(fs.stat)
async function run () {
  console.log(await stat('.'))
}
run()

Once

Implementation:

 const once = require('events.once')

The same once as provided in Node core (also polyfilled for earlier Node 10 versions).

Example:

 const { once } = require('nonsynchronous')
const http = require('http')
async function run () {
  const server = http.createServer()
  server.listen()
  await once(server, 'listening')
  console.log(server.address())
}
run()

When

Useful for when you want to explicitly use a callback based API within an async function. The function returned from when
must be called after awaiting the done method on that function
other wise an error called before awaiting done() will be thrown.

Implementation:

 const when = () => {
  var done = () => { throw Error('called before awaiting done()') }
  const fn = () => done()
  fn.done = promisify((cb) => { done = cb })
  return fn
}

Example:

 const { when } = require('nonsynchronous')
async function run () {
  const until = when()
  setTimeout(() => {
    until()
  }, 1000)
  await until.done()
  console.log('timeout complete')
}
run()

Whenify

Useful for using a callback based API within an async function
without any modifications required within the callback itself.

Must be used with a callback last API (for callback first, just use when manually).

Used in conjunction with the done symbol and optionally
the count symbol. The asyncOps option is explored in the count symbol documentation.

Implementation:

 const whenify = (fn, { asyncOps } = { asyncOps: 1 }) => {
  const until = when()
  const max = asyncOps - 1
  const result = (...args) => {
    const cb = args.pop()
    return fn(...args, (...args) => {
      cb(...args) // eslint-disable-line
      if (++result[count] > max) until()
    })
  }
  result[count] = 0
  Object.defineProperty(result, done, {
    get () { return until.done() }
  })
  return result
}

Example:

 const { whenify, done } = require('nonsynchronous')
const fs = require('fs')
async function run () {
  const stat = whenify(fs.stat)
  stat('.', (err, stats) => {
    console.log(err, stats)
  })
  await stat[done]
}
run()

Whenify Method

Whenify an object method so that method[done] can be awaited (where done is the done symbol). This can be particularly useful when writing tests for an instance with callback based methods. The test be both self documenting and async compatible.

Implementation:

 const whenifyMethod = (instance, method, opts) => {
  const result = whenify(instance[method].bind(instance), opts)
  instance[method] = result
  return instance
}

Example:

 const { whenifyMethod, done } = require('nonsynchronous')
const fs = require('fs')
whenifyMethod(fs, 'stat')
async function run () {
  fs.stat('.', (err, stats) => {
    console.log(err, stats)
  })
  await fs.stat[done]
}
run()

Promisify Method

Convert a callback-based method on an instance into its
promisifed equivalent. Can be passed multiple method names
to easily promisify entire instances.

Implementation:

 const _promisifyMethod = (instance, method) => {
  const result = promisify(instance[method])
  instance[method] = result
  return instance
}
const promisifyMethod = (instance, ...methods) => {
  methods.forEach(_promisifyMethod.bind(null, instance))
  return instance
}

Example:

 const { promisifyMethod } = require('nonsynchronous')
const http = require('http')
async function run () {
  const server = http.createServer()
  promisifyMethod(server, 'listen')
  await server.listen()
  console.log(server.address())
}
run()

Promisify Of

Partially apply a promisify of a particular method on any given instance
without mutating the instance. This is useful as an alternative to promisifyMethod if you don't want to overwrite instance keys and/or
you have multiple different instances that you want to promisify the same
method of.

Implementation:

 const promisifyOf = (method) => {
  return (instance) => promisify((...args) => instance[method](...args))
}

Example:

 const { promisifyOf } = require('nonsynchronous')
const http = require('http')
async function run () {
  const server = http.createServer()
  const listen = promisifyOf('listen')
  await listen(server)(2000) // listen on port 2000
  console.log(server.address())
}
run()

Immediate

Promisified setImmediate.

Implementation:

 const immediate = promisify(setImmediate)

Example:

 const { immediate } = require('nonsynchronous')
async function run () {
  console.log('this tick')
  await immediate()
  console.log('next tick')
}
run()

Timeout

Promisified setTimeout.

Implementation:

 const timeout = promisify(setTimeout)

Example:

 const { timeout } = require('nonsynchronous')
async function run () {
  await timeout(1000)
  console.log('timeout complete')
}
run()

Symbols

Done

The done symbol is used with whenify and whenifyMethod
to access a promise on the function that has been whenified
which can be awaited. The promise will complete once the
callback for a whenified function has been called.

Count

The count symbol is used with whenify and whenifyMethod to access a the total amount
of times a whenified functions callback was called. This is
only useful when you set the asyncOps option to greater
than 1.

 const { whenify, done, count } = require('nonsynchronous')
const multiCallbackThing = whenify(
  require('multi-callback-thing'),
  {asyncOps: 3} // expecting three calls of the callback
)
async function run () {
  multiCallbackThing(() => {
    // how many times has this cb been called so far?
    // note: the count is zero indexed.
    console.log(`called ${multiCallbackThing[count] + 1} times`) 
  })
}
run()

Custom Promisify Args

The customPromisifyArgs symbol exposes a Node core symbol used
to alter promisify behaviour for callbacks then
have extra arguments.

 const { promisify, customPromisifyArgs } = require('nonsynchronous')
const multiArgApi = (cb) => setImmediate(cb, null, 'circle', 'red')
multiArgApi[customPromisifyArgs] = ['shape', 'color']
const multiValApi = promisify(multiArgApi)

async function run () {
  const { shape, color } = await multiValApi()
  console.log(`shape: ${shape}\ncolor: ${color}`)
}
run()

Behaviors

Automatically includes and enable make-promisies-safe which causes Node to treat unhandled rejections as unhandled exceptions (e.g. throws and exits).

Tests & Coverage

 npm test
Suites:   1 passed, 1 of 1 completed
Asserts:  24 passed, of 24
----------|----------|----------|----------|----------|-------------------|
File      |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
----------|----------|----------|----------|----------|-------------------|
All files |      100 |      100 |      100 |      100 |                   |
 index.js |      100 |      100 |      100 |      100 |                   |
----------|----------|----------|----------|----------|-------------------|

License

MIT

Dependencies

RELATED POST

10 Must-Know Windows Shortcuts That Will Save You Time

10 Must-Know Windows Shortcuts That Will Save You Time

Arrays vs Linked Lists: Which is Better for Memory Management in Data Structures?

Arrays vs Linked Lists: Which is Better for Memory Management in Data Structures?

Navigating AWS Networking: Essential Hacks for Smooth Operation

Navigating AWS Networking: Essential Hacks for Smooth Operation

Achieving Stunning Visuals with Unity's Global Illumination

Achieving Stunning Visuals with Unity's Global Illumination

Nim's Hidden Gems: Lesser-known Features for Writing Efficient Code

Nim's Hidden Gems: Lesser-known Features for Writing Efficient Code