Skip to content

Instantly share code, notes, and snippets.

@OliverJAsh
Last active August 29, 2015 14:09
Show Gist options
  • Save OliverJAsh/0c755bd05219fb8011cf to your computer and use it in GitHub Desktop.
Save OliverJAsh/0c755bd05219fb8011cf to your computer and use it in GitHub Desktop.
wrap: Nodeify the result of a promise returning function.

wrap

Nodeify the result of a promise returning function.

When an API requires that you pass it a function with the signature (...args, cb), wrap is a small helper that allows you to instead pass a promise returning function. wrap will nodeify the result of the promise returning function (fulfilment or rejection) by passing its value to the original callback.

Example

One such API that asks for an asynchronous listener function (...args, cb) is express. When a HTTP request is made, express will call your listener function, if you have one registered for that route. The example below demonstrates how wrap can help you to use promises in such a situation.

// 1. The traditional callback (next)
app.get('/', (req, res, next) => {
    next(new Error('Example error'));
});

// 2. If you want to use promises, you must remember to manually nodeify. That
// it to say, "call the callback with the result of the promise (fulilment
// or rejection)."
app.get('/', (req, res, next) => {
    return Q.reject(new Error('Example error'))
        .nodeify(next);
});

// 3. wrap nodeifies the promise for you.
app.get('/', wrap((req, res) => {
    return Q.reject(new Error('Example error'));
}));

To run the express example:

npm install
node traceur-runner.js express-example.js
import wrap from './wrap';
import Q from 'q';
import express from 'express';
var app = express();
app.get('/', wrap((req, res) => {
return Q.reject(new Error('Example error'));
}));
// Error handler: arity must be 4
app.use((error, req, res, next) => {
console.error('Express error handler:', error.stack);
res
.type('text/plain')
.status(500)
.send(error.stack);
});
var server = app.listen(3000, () => {
var { host, port } = server.address();
console.log('Example app listening at http://%s:%s', host, port);
});
{
"name": "wrap",
"version": "0.0.0",
"description": "Nodeify the result of a promise returning function.",
"main": "wrap.js",
"author": "Oliver Joseph Ash <[email protected]>",
"dependencies": {
"lodash-node": "^2.4.1",
"q": "^1.1.1"
},
"devDependencies": {
"express": "^4.10.2",
"traceur": "0.0.74",
"traceur-source-maps": "^1.0.5"
}
}
'use strict';
var traceur = require('traceur');
require('traceur-source-maps').install(traceur);
var path = require('path');
traceur.require.makeDefault(function (modulePath) {
var isDependency = modulePath.indexOf('node_modules') !== -1;
return ! isDependency;
});
require(path.resolve(process.cwd(), process.argv[2]));
import Q from 'q';
import toArray from 'lodash-node/modern/collections/toArray';
export default function wrap(promiseReturningFn) {
// ES5 function so we can access the arguments of *this* function
return function () {
var callback = arguments[arguments.length - 1];
var argumentsWithoutCallback = toArray(arguments).slice(0, -1);
var promise = promiseReturningFn(...argumentsWithoutCallback);
// Cast to Q so we can use the nodeify helper
Q(promise).nodeify(callback);
};
}
@OliverJAsh
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment