Bluebird promisify and callback with no error argument - node.js

I'm trying to promisify a 3rd party library that doesn't use the callback(err, data) pattern. Instead they always return callback(data) and throw on errors.
Promise.promisifyAll(horse);
var p = Promise.defer();
horse.drinkAsync()
.error(function(data)
{
p.fulfill(data);
})
.catch(function (err)
{
console.error('error occured', err);
});
return p.promise;
What is a nice way to wrap such a behavior with promises and still have it look ok and allow to catch the thrown error? The catch clause doesn't trigger and the application crashes.

From Bluebird 2.1 on, you can now customize promisifyAll with a custom promisification handler:
function noErrPromisifier(originalMethod){
return function promisified() {
var args = [].slice.call(arguments); // might want to use smarter
var self = this // promisification if performance critical
return new Promise(function(resolve,reject){
args.push(resolve);
originalMethod.apply(self,args); // call with arguments
});
};
}
var horse = Promise.promisifyAll(require("horse"), {
promisifier: noErrPromisifier
});
horse.drinkAsync().then(function(data){
// Can use here, ow promisified normally.
});
If the original method throws asynchronously, there is really no way around wrapping it in a domain, although I've never seen a library that acts that poorly.

Related

New to NodeJS - is it possible to await a callback function?

What if I have a code like this:
var mysql = require('mysql');
var pool = mysql.createPool(...);
pool.getConnection(function(err, connection) {
if (err) throw err; // not connected!
// Use the connection
connection.query('SELECT something FROM sometable', function (error, results, fields) {
// When done with the connection, release it.
connection.release();
// Handle error after the release.
if (error) throw error;
// Don't use the connection here, it has been returned to the pool.
});
});
The logic from initializing the pool until the entire getConnection process is located in an async function. So what happens is, when deployed in AWS, logs in getConnection are not logged because the handler finishes execution before the callback is processed. Due to this, the logs from line "if (err) throw err" is not seen in AWS cloudwatch logs.
Is there a workaround for this? I simply want to await the callback function in pool.getConnection
I did my research but all I found were specific implementations for specific scenarios, none quite similar to my scenario.
is it possible to await a callback function?
No, not with a plain callback that does not use promises.
await only does something useful when you're awaiting a promises. The connection.query() function call you show in your question does NOT use promises so there is no place for await with that function call as it is.
But, you can either wrap the connection.query() in a function that returns a promise (referred to as promisifying it) and create a new function that is promise-based.
Here's a look at how promisifying works. You don't show the overall context of your code. The promisifying would more typically be done at a more centralized location, but I've shown it here in the only context that you've shown:
const { promisify } = require('util');
async function someFunc() {
const pool = mysql.createPool(...);
pool.getConnectionP = promisify(pool.getConnection);
let connection;
try {
connection = await pool.getConnectionP();
connection.queryP = promisify(connection.query);
const results = await connection.queryP('SELECT something FROM sometable');
return results;
} catch(e) {
console.log(e);
// handle errors here
} finally {
if (connection) {
connection.release();
}
}
}
Or, your database already has a promise-interface and you can just use that (which would be my recommendation). See the mysql2/promise interface here where these functions are already converted to use promises and you can then use await with them.

NodeJS Express Async issue

I have this function which gets some data from my database but i'm having a trouble calling the function and getting the proper response
function getEvents()
{
var x = [];
var l = dbCollection['e'].find({}).forEach(function(y) {
x.push(y);
});
return x;
});
and another function which calls this function but it always returns undefined.
How can i make the function wait till mongoose has finished filling up the array?
Thanks for the help! My life
dbCollection['e'].find is called non-blocking way so you are returning x before filling. You need to use callbacks or some mongoose promises. You can get all returning values from database like following snippet
function getEvents(callback) {
dbCollection['e'].find({}, function(error, results) {
// results is array.
// if you need to filter results you can do it here
return callback(error, results);
})
}
Whenever you need to call getEvents function you need to pass a callback to it.
getEvents(function(error, results) {
console.log(results); // you have results here
})
You should read mongoose docs for how queries work.
There is also support for promises in mongoose. You can check this url for more information about promises.
The solution proposed by #orhankutlu should work fine.
I will give another solution using promise. You can choose one between these two solutions depending on your style of programming.
Solution using promise:
function getEvents() {
return new Promise(function(resolve, reject){
dbCollection['e'].find({}, function(error, results) {
if (error) return reject(error);
var x = [];
results.forEach(function(y){
x.push(y);
});
// forEach() is a blocking call,
// so the promise will be resolved only
// after the forEach completes
return resolve(x);
});
});
};
Calling getEvents():
getEvents().then(function(result){
console.log(result); //should print 'x'
}).catch(function(err){
// Handle error here in case the promise is rejected
});
I will encourage you to try both the approaches, ie, using callbacks and using promises. Hope you find it useful!

Node.js consecutive method calls with nested callback formatting

So I'm new to Node.js and Im just wondering if the way I have my code setup makes sense. Im coming from a Java background so the nested callback structure is new. I have a Node program that runs a bunch of code that I broke down into different methods. The thing is that the methods need to be called in order. My code has this structure right now:
functionOne(data, callback(err) {
functionTwo(data, callback(err) {
functionThree(data, callback(err) {
functionFour(data, callback(err) {
//Code
});
});
});
});
This is very minimalistic, but is this structure ok? With Java, I'd take the return values of all the methods, then just pass them to the next function. From my understanding so far, the Java approach I just mentioned is one of the main things that Node.js was trying to eliminate. But anyway... Does that structure look ok, and is that how its intended to look? Just want to be sure that I'm not making any major errors with Node in general. Thanks!
Your code structure looks fine if you work with callback pattern.
But if you're interested in make your code cleaner and readable you would like to use Promises in your asynchronous function, so instead of pass a callback to your functions you could do something like this :
function asyncFunction (data){
return new Promise(function(resolve, reject){
// Do something with data
// Here you can call reject(error) to throw an error
resolve();
});
}
And instead of nested function callbacks you can call then method of Promise.
asyncFunction(data)
.then(function(){
// Promise resolved
// Something has been done with data
});
With Promises you can also execute async fuctions in parallel :
Promise.all([asyncFunctionA(data), asyncFunctionB(data), asyncFunctionC(data)])
.then(function(){...});
EDIT
If you need to pass values of one function to another, your code should look like this :
asyncFunctionA(data)
.then(function(dataA){
return asyncFunctionB(dataA);
})
.then(function(dataB){
return asyncFunctionC(dataB);
})
.then(function(dataC){
// ...
});
You should try to use promises to avoid your callback hell, so it could be something like these...
const Q = require('q'); // you can do a research for this module.
var myModule = {};
myModule.functionOne = (params) => {
const deferred = Q.defer(); // wait for this to complete
// body function
deferred.resolve(data); // this would be the result of this function
return deferred.promise; // data is the output on your function
}
myModule.functionTwo = (params) => {
const deferred = Q.defer(); // wait for this to complete
// body function
deferred.resolve(data); // this would be the result of this function
return deferred.promise; // data is the output on your function
}
myModule.doAll = (params) => {
myModule.functionOne(params)
.then((outputFunctionOne) => {
// this is called after functionOne ends
return myModule.functionTwo(outputFunctionOne);
})
.then((outputFunctionTwo) => {
// this is called after function 2 ends
if (outputFunctionTwo.success) {
// if everything ok, resolve the promise with the final output
deferred.resolve(outputFunctionTwo);
} else {
// reject the promise with an error message
deferred.reject('error');
}
})
.fail((err) => {
// this is call if the promise is rejected or an exception is thrown
console.log(err); // TODO: Error handling
})
.done();
}
module.exports = myModule;
You can Chain as many promises as you want really easily, that way you get rid of the callback hell. Best part, you can do promises on Javascript or Node.js
Reference Link https://github.com/kriskowal/q
Hope this helps
Most of the other answers give Promise/A as the answer to your callback woes. This is correct, and will work for you. However I'd like to give you another option, if you are willing to drop javascript as your working language.
Introducing Iced Coffee, a branch of the CoffeeScript project.
With Iced Coffee you would write:
await functionOne data, defer err
await functionTwo data, defer err2
await functionThree data, defer err3
//etc
This then compiles to the CoffeeScript:
functionOne data, (err) ->
functionTwo data, (err2) ->
functionThree data, (err3) ->
//etc
Which then compiles to your Javascript.
functionOne(data, callback(err) {
functionTwo(data, callback(err2) {
functionThree(data, callback(err3) {
//etc
});
});
});

What is cb() in Node?

Where are people getting cb() from, is this a Node thing or vanilla JS thing?
For example:
Managing Node.js Callback Hell with Promises, Generators and Other Approaches
they're using cb() to I guess callback and return an error or a value or both in some cases depending on what the callback function sig is?
cb in the context you're describing it is how a vanilla callback function is passed into a (typically) asynchronous function, which is a common pattern in node.js (it's sometimes labelled next, but you can call it bananas if you so desire - it's just an argument).
Typically the first argument is an error object (often false - if all went as planned) and subsequent arguments are data of some form.
For example:
function myAsyncFunction(arg1, arg2, cb) {
// async things
cb(false, { data: 123 });
}
then using this function:
myAsyncFunction(10, 99, function onComplete(error, data) {
if (!error) {
// hooray, everything went as planned
} else {
// disaster - retry / respond with an error etc
}
});
Promises are an alternative to this design pattern where you would return a Promise object from myAsyncFunction
For example:
function myAsyncFunction2(arg1, arg2) {
return new Promise(function resolution(resolve, reject, {
// async things
resolve({ data: 123 });
});
}
then using this function:
myAsyncFunction2(10, 99)
.then(function onSuccess(data) {
// success - send a 200 code etc
})
.catch(function onError(error) {
// oh noes - 500
});
They're basically the same thing, just written slightly differently. Promises aren't supported especially widely in a native form, but if put through a transpiler (I'd recommend babel) during a build step they should perform reliably enough in a browser too.
Callbacks will always work in a browser with no shimming / transpilation.
node.js has lots of asynchronous operations that take a completion callback as an argument. This is very common in various node.js APIs.
The node.js convention for this callback is that the first argument passed to the callback is an error code. A falsey value for this first argument means that there is no error.
For example:
fs.readFile("test.txt", function(err, data) {
if (!err) {
console.log("file data is: " + data);
}
});
A function you create yourself may also define it's own callback in order to communicate the end of one or more asynchronous operations.
function getData(id, cb) {
var fname = "datafile-" + id + ".txt";
fs.readFile(fname, function(err, data) {
if (err) {
cb(err);
} else if (data.slice(0, 6) !== "Header"){
// proper header not found at beginning of file data
cb(new Error("Invalid header"));
} else {
cb(0, data);
}
});
}
// usage:
getData(29, function(err, data) {
if (!err) {
console.log(data);
}
});
From the Vanilla JS, you can declare a function and pass throuw parameters a declaration of another function, that can called async
https://developer.mozilla.org/en-US/docs/Glossary/Callback_function

making mongoskin function is asynchronous sync

User.prototype.isUnique = function () {
var result;
db.user.count({name:'abcdefg'}, function(err, count){
console.log('the count is: ' + count);
result = count;
});
return result;
}
this function is used to find out if this user is unique, but the return result is always 'undefined' since db operation is async. I believe it is a common problem in nodejs.
How do I solve it?
I try to use promise (https://npmjs.org/package/promise), but I don't have enough knowledge to understand their documentation. It's for very advanced developer.
Can you help me with some sample code? All I need to do is get the count() using mongoskin, and then return the result in this member method.
Thanks!
It's not a common problem, it's just how Node works and something that you'll have to get used to dealing with.
The simplest solution (also a very common one) is to provide a callback function from the calling code. That function will be called whenever the asynchronous action is finished:
User.prototype.isUnique = function(callback) {
db.user.count({name:'abcdefg'}, function(err, count){
console.log('the count is: ' + count);
callback(err, count);
});
}
// in your calling code:
user.isUnique(function(err, count) {
if (err) ...; // TODO: handle error
...
});
It's also common in Node to have callback functions accept at least one argument which contains an error object if an error occurred, or null if everything went okay.
In the code above I'm passing any errors that may have occurred during the call to db.user.count to the callback function. It's up to the calling code to deal with any errors.
There are several alternatives to dealing with asynchronous code. One would be to use promises, like you mention. There are also solutions like streamline that make asynchronous code look like it is synchronous, but it requires that you 'compile' your code (although this can also be done at runtime) before you can use it.
EDIT: if you want to use promises, you can use this:
var Promise = require('promise');
User.prototype.isUnique = function() {
return Promise(function(resolve, reject) {
db.user.count({name:'abcdefg'}, function(err, count){
if (err) {
console.log('an error occurred:', err);
reject(err);
} else {
console.log('the count is:', count);
resolve(count);
}
});
});
};
// in your calling code:
user.isUnique().then(function(count) {
...
}, function(err) {
...
});
(this requires that the promise package is installed)

Resources