Skip to content

Instantly share code, notes, and snippets.

@elmigranto
Last active February 10, 2017 14:21
Show Gist options
  • Save elmigranto/f5a5beaf8426a62565e8e7ed0cf5fb4a to your computer and use it in GitHub Desktop.
Save elmigranto/f5a5beaf8426a62565e8e7ed0cf5fb4a to your computer and use it in GitHub Desktop.
awaitability
'use strict';
// awaitable(fn, [arg1, [arg2[, ..., argN]]])
// Always returns array of results.
const awaitableSpread = (fn, ...args) => {
if (typeof fn !== 'function')
throw new Error(`awaitable() needs a function as first argument, got "${typeof func}"`);
return new Promise((resolve, reject) => {
fn.call(null, ...args, (err, ...results) => {
return err
? reject(err)
: resolve(results);
});
});
};
// Same as awaitableSpread() except always returns first result.
const awaitable = async (...everything) => (await awaitableSpread(...everything))[0];
module.exports = awaitable;
module.exports.spread = awaitableSpread;
'use strict';
const fs = require('fs');
const dns = require('dns');
const awaitable = require('../src/awaitable');
const main = async () => {
// Use awaitabale() when:
// - callback() is invoked with single argument;
// - or you only interested in the first argument anyways.
const stat = await awaitable(fs.stat, __filename);
const address = await awaitable(dns.lookup, 'localhost');
// Here's an example of how to pass multiple arguments
// and access multiple callback() arguments using destructuring.
const source = await awaitable(fs.readFile, __filename, 'utf8');
const [address6, family6] = await awaitable.spread(dns.lookup, 'localhost', 6);
console.log({ // eslint-disable-line no-console
stat,
source,
address,
address6, family6
});
};
if (!module.parent)
main();
'use strict';
const awaitable = require('../src/awaitable');
describe('awaitable()', () => {
it('awaitable.spread(fn)', async () => {
const callbackApi = (cb) => setImmediate(cb);
await awaitable.spread(callbackApi);
});
it('awaitable.spread(fn, oneArg)', async () => {
const callbackApi = (x, cb) => setImmediate(cb, null, x);
const result = await awaitable.spread(callbackApi, 1);
expect(result).to.eql([1]);
});
it('awaitable.spread(fn, multiple, argu, ments)', async () => {
const callbackApi = (x, y, z, cb) => setImmediate(cb, null, x, y, z);
const result = await awaitable.spread(callbackApi, 1, 2, 3);
expect(result).to.eql([1, 2, 3]);
});
it('awaitable.spread(non-function) throws', () => {
expect(() => awaitable.spread(42)).to.throw(/needs a function/);
});
describe('awaitable() always returns first argument', () => {
const callbackApi = (...args) => setImmediate(args[args.length - 1], null, ...args.slice(0, -1));
it('no arguments', async () => {
expect(await awaitable(callbackApi)).to.equal(undefined);
});
it('single argument', async () => {
expect(await awaitable(callbackApi, 1)).to.equal(1);
});
it('multiple arguments', async () => {
expect(await awaitable(callbackApi, ...[1, 2, 3])).to.equal(1);
});
});
describe('awaitable.spread() always returns array', () => {
const callbackApi = (...args) => setImmediate(args[args.length - 1], null, ...args.slice(0, -1));
it('no arguments', async () => {
expect(await awaitable.spread(callbackApi)).to.eql([]);
});
it('single argument', async () => {
expect(await awaitable.spread(callbackApi, ...[1])).to.eql([1]);
});
it('multiple arguments', async () => {
expect(await awaitable.spread(callbackApi, ...[1, 2, 3])).to.eql([1, 2, 3]);
});
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment