.. | ||
lib | ||
index.js | ||
LICENSE | ||
package.json | ||
README.md |
release-zalgo
Helps you write code with promise-like chains that can run both synchronously and asynchronously.
Installation
$ npm install --save release-zalgo
Usage
If you use this module, you’ll release Ẕ̶̨̫̹̌͊͌͑͊̕͢͟a̡̜̦̝͓͇͗̉̆̂͋̏͗̍ͅl̡̛̝͍̅͆̎̊̇̕͜͢ģ̧̧͍͓̜̲͖̹̂͋̆̃̑͗̋͌̊̏ͅǫ̷̧͓̣͚̞̣̋̂̑̊̂̀̿̀̚͟͠ͅ. You mustn’t do that.
Before you proceed, please read this great post by Isaac Schlueter on Designing APIs for Asynchrony.
The first rule of using this package is to keep your external API consistent.
The second rule is to accept the burden of controlling Ẕ̶̨̫̹̌͊͌͑͊̕͢͟a̡̜̦̝͓͇͗̉̆̂͋̏͗̍ͅl̡̛̝͍̅͆̎̊̇̕͜͢ģ̧̧͍͓̜̲͖̹̂͋̆̃̑͗̋͌̊̏ͅǫ̷̧͓̣͚̞̣̋̂̑̊̂̀̿̀̚͟͠ͅ by ensuring he does not escape your API boundary.
With that out of the way… this package lets you write code that can
run both synchronously and asynchronously. This is useful if you have
fairly complex logic for which you don’t want to write multiple
implementations. See package-hash
for instance.
This is best shown by example. Let’s say you have a
hashFile()
function:
const crypto = require('crypto')
const fs = require('fs')
function hashFile (file) {
return new Promise((resolve, reject) => {
.readFile(file, (err, buffer) => err ? reject(err) : resolve(buffer))
fs
}).then(buffer => {
const hash = crypto.createHash('sha1')
.update(buffer)
hashreturn hash.digest('hex')
}) }
A synchronous version could be implemented like this:
function hashFileSync (file) {
const buffer = fs.readFileSync(file)
const hash = crypto.createHash('sha1')
.update(buffer)
hashreturn hash.digest('hex')
}
Here’s the version that uses release-zalgo
:
const crypto = require('crypto')
const fs = require('fs')
const releaseZalgo = require('release-zalgo')
const readFile = {
async (file) {
return new Promise((resolve, reject) => {
.readFile(file, (err, buffer) => err ? reject(err) : resolve(buffer))
fs
}),
}
sync (file) {
return fs.readFileSync(file)
}
}
function run (zalgo, file) {
return zalgo.run(readFile, file)
.then(buffer => {
const hash = crypto.createHash('sha1')
.update(buffer)
hashreturn hash.digest('hex')
})
}
function hashFile (file) {
return run(releaseZalgo.async(), file)
}
function hashFileSync (file) {
const result = run(releaseZalgo.sync(), file)
return releaseZalgo.unwrapSync(result)
}
Note how close the run()
implementation is to the
original hashFile()
.
Just don’t do this:
function badExample (zalgo, file) {
let buffer
.run(readFile, file)
zalgo.then(result => { buffer = result })
const hash = crypto.createHash('sha1')
.update(buffer)
hashreturn hash.digest('hex')
}
This won’t work asynchronously. Just pretend you’re working with promises and you’ll be OK.
API
First require the package:
const releaseZalgo = require('release-zalgo')
releaseZalgo.sync()
Returns a zalgo
object that runs code synchronously:
const zalgo = releaseZalgo.sync()
releaseZalgo.async()
Returns a zalgo
object that runs code
asynchronously:
const zalgo = releaseZalgo.async()
releaseZalgo.unwrapSync(thenable)
Synchronously unwraps a thenable, which is returned when running synchronously. Returns the thenables fulfilment value, or throws its rejection reason. Throws if the thenable is asynchronous.
zalgo.run(executors, ...args)
When running synchronously, executors.sync()
is called.
When running asynchronously executors.async()
is used. The
executer is invoked immediately and passed the remaining arguments.
For asynchronous execution a Promise
is returned. It is
fulfilled with executors.async()
’s return value, or
rejected if executors.async()
throws.
For synchronous execution a thenable is returned. It has the same methods
as Promise
except that callbacks are invoked immediately.
The thenable is fulfilled with
executors.sync()
’s return value, or rejected if
executors.sync()
throws.
zalgo.all(arr)
When running synchronously, returns a new thenable which is fulfilled with an array, after
unwrapping all items in arr
.
When running asynchronously, delegates to
Promise.all(arr)
.
zalgo.returns(value)
When running synchronously, returns a new thenable which is fulfilled with
value
.
When running asynchronously, delegates to
Promise.resolve(value)
.
zalgo.throws(reason)
When running synchronously, returns a new thenable which is rejected with
reason
.
When running asynchronously, delegates to
Promise.reject(reason)
.
Thenables
Thenables are returned when running sychronously. They’re much like
Promise
s, in that they have then()
and
catch()
methods. You can pass callbacks and they’ll be
invoked with the fulfilment value or rejection reason. Callbacks can
return other thenables or throw exceptions.
Note that then()
and catch()
must be called
on the thenable, e.g. thenable.then()
, not
(thenable.then)()
.
Thenables should not be exposed outside of your API. Use
releaseZalgo.unwrapSync()
to unwrap them.