Why does 'promisify' cause node to ignore a function? - node.js

I wrote the following code:
var express = require('express');
var app = express();
var Promise = require('bluebird');
var counter = {};
counter.num = 0;
function incr(counter) {
counter.num = counter.num + 1;
}
app.get('/check', function(req, res) {
Promise.promisify(console.log)(counter.num)
.then(Promise.promisify(incr)(counter.num))
.then(console.log(counter.num));
res.end("OK");
});
app.listen(4000);
I expect the following operations to take place synchronically:
1. print counter.num (=0)
2. increment counter.num
3. print the new counter.num (=1)
This is what I get:
0 [Function]
0
Why didn't operation 2 take place? and Why do I get a "[Function]" in the console?

Your situation is not appropriate for Promise.promisify().
Assuming you are using Bluebird, then Bluebird's Promise.promisify() expects the following:
The function you're promisifying must take a callback as it last argument (often referred to as the node.js async calling convention).
That callback must be called with the argument (err, data) when the function has completed its operation.
The err value must be falsey when the function is successful and the result is passed in the data argument. The err value must be truthy when there is an error and then err is the error value.
Your use of .promisify() does not match any of these conditions.
Since the purpose of promises is to track or coordinate asynchronous operations, it does not appear that you should even be using promises for this particular code. Because all your counter operations are synchronous you can just do this:
app.get('/check', function(req, res) {
console.log(counter.num);
incr(counter);
console.log(counter.num);
res.end("OK");
});

promisify is for async functions. console.log is a sync function. Bluebird expects function to be promisified has callback function for last arguments.
And I don't see any reason you might want to use promise in your question situation.

Related

return value of a callback function in Node.js

I have a question about callback functions. Consider this simple code:
var array = [1,2,3];
console.log(array.map(function(val){
return val * 2
}))
This will correctly log back to the console [2,4,6] which means it is "returning" that value back.
Now consider this (NOTE: assume "ab" to be a valid directory)
fs.readdir("ab",function(err,data){
console.log(data)
})
This code works fine and will print an array of filenames in the directory "ab" to the terminal. However, the same code:
console.log(fs.readdir("ab",function(err,data){
return data
}))
This will print undefined.. why is this? if in the previous snippet I can log data to the terminal, why can't I return the value and log it to the console? And how is the first snippet including the map method working using this same logic?
Thank you.
fs is an Asynchronous function, it doesn't return the values as it doesn't know when the value will be available due to which it logs undefined.
When you say console.log(fs.readdir()), it reads the fs function and checks if it is returning anything which in this case is undefined and hence logs it. The execution didn't go inside the callback of fs.readdir() yet as it is asynchronous as takes time for that to complete.
fs.readdir() is like a promise, it calls to read the directory and forget about it till the reading operation is done and after which it's callback function is called.
Hence, we pass callback functions which will be called back when the asynchronous operation is done executing like below :
function readFile (callback){
fs.readdir("ab",function(err,data){
return callback(data);
});
}
readFile(function (data){
console.log(data);
});
Because the map() method by definition returns an array, and fs.readdir() returns undefined.
Why it returns undefined is because it is an asynchronous function, the result is not returned by the function but in the callback you have to wait, that's because you have to do the console.log inside that callback function.
Just for your information, the fs module has synchronous version of the methods as well, so in this case you could do:
console.log(fs.readdir("ab"))
But using the synchronous version you are blocking your code until you get the result, so it would not be recommended depending on the situation; that's up to your case.
I hope that the following will help someone else having similar problem with reading values from MongoDB using socket io.
In those cases you can use the following code (both functions on server side):
socket.on('readTopicMessages', (intGr, callback) => {
readTopicChats(intGr, function (data){
io.emit('topicMessages', data);
});
});
function readTopicChats (intGr, callback){
All_Chats
.find({ 'intGr': intGr.intGr })
.sort([['dateTime', 'ascending']])
.exec(function (err, data){
return callback(data);
});
}

What is the scope for a function's arguments when dealing with inner asynchronous calls?

In my following example the arguments of one of the express app callbacks are behaving differently depending on if they are encapsulated inside an auxiliary function or not. I have solved my problem but I would like to understand better what is happening here.
getItem and buildView return promises created with Q.
The following code works (i. e. no fail callback is ever called):
var app = require("express")();
app.get('/item/:itemId', function(req, res){
var showItem= function(item){
var s = function(x){res.send(x);};
buildView(item).then(s).fail(console.log);
};
var showError = function(error){
res.send(error.message);
};
getItem(req.params.exception_id)
.then(showItem).fail(showError);
});
And the following code doesn't (console.log prints [TypeError: Cannot read property 'req' of undefined]):
var app = require("express")();
app.get('/item/:itemId', function(req, res){
var showItem= function(item){
buildView(item).then(res.send).fail(console.log);
};
var showError = function(error){
res.send(error.message);
};
getItem(req.params.exception_id)
.then(showItem).fail(showError);
});
(The difference is in the fourth and fifth lines, the fourth is deleted and the fifth is modified).
It is clear that the promise buildView is being resolved successfully, otherwise the first approach would fail as well; and until the point where buildView is applied both implementations have followed exactly the same steps.
Why are not these implementations getting exactly the same?
Shouldn't it be that when the promise buildView is resolved .then(res.send) should execute res.send with the resolved value of the promise as its argument? (i. e. the first implementation).
The following will work:
buildView(item).then(res.send.bind(res)).fail(console.log);
When you simply do then(res.send), this context of res is lost: send function is detached from res object context.
It has nothing to do with asynchronicity as this is a known feature of this in JavaScript.

How can I use Socket.IO with promises?

As a part of an ongoing effort, I'm changing my current callbacks technique to promises using blue-bird promise library.
I would like to implement this technique with Socket.IO as well.
How can I use Socket.IO with promises instead of callbacks?
Is there any standard way of doing it with Socket.IO? any official solution?
You might look into Q-Connection, which facilitates RPC using promises as proxies for remote objects and can use Socket.IO as a message transport.
Bluebird (and many other promise libraries) provide helper methods to wrap your node style functions to return a promise.
var readFile = Promise.promisify(require("fs").readFile);
readFile("myfile.js", "utf8").then(function(contents){ ... });
https://github.com/petkaantonov/bluebird/blob/master/API.md#promisification
Returns a function that will wrap the given nodeFunction. Instead of
taking a callback, the returned function will return a promise whose
fate is decided by the callback behavior of the given node function.
The node function should conform to node.js convention of accepting a
callback as last argument and calling that callback with error as the
first argument and success value on the second argument.
have a look here https://www.npmjs.com/package/socket.io-rpc
var io = require('socket.io').listen(server);
var Promise = require('bluebird');
var rpc = require('socket.io-rpc');
var rpcMaster = rpc(io, {channelTemplates: true, expressApp: app})
//channelTemplates true is default, though you can change it, I would recommend leaving it to true,
// false is good only when your channels are dynamic so there is no point in caching
.expose('myChannel', {
//plain JS function
getTime: function () {
console.log('Client ID is: ' + this.id);
return new Date();
},
//returns a promise, which when resolved will resolve promise on client-side with the result(with the middle step in JSON over socket.io)
myAsyncTest: function (param) {
var deffered = Promise.defer();
setTimeout(function(){
deffered.resolve("String generated asynchronously serverside with " + param);
},1000);
return deffered.promise;
}
});
io.sockets.on('connection', function (socket) {
rpcMaster.loadClientChannel(socket,'clientChannel').then(function (fns) {
fns.fnOnClient("calling client ").then(function (ret) {
console.log("client returned: " + ret);
});
});
});

node kriskowal/q promise stack errors on chaining promises

The following code errors out on the first .then with:
/Users/danielbyrne/working/mite_npm/mite.js:48
.then(configMan.validateSettings(parsedData))
ReferenceError: parsedData is not defined
I don't understand why this code is failing.
The call:
parseConfigurationFile(path.join(__dirname,'file.config'))
.then(validateSettings(parsedData));
The functions it calls:
function parseConfigurationFile(fileName) {
var readFile = q.nfbind(fs.readFile);
readFile(fileName,"utf-8")
.then(function(data) {
var deferred = q.defer();
// Return the Config 'settings' in JSON
deferred.resolve(JSON.parse(data));
return deferred.promise;
});
}
function vaidateSettings (data) {...}
The only way this works is if I change the function validateSettings to an anonymous function and place it inline like this :
parseConfigurationFile(path.join(__dirname,'file.config'))
.then(function(parsedData){...});
Why can i not chain named functions in this manner?
Your validateSettings call should be like this:
parseConfigurationFile(path.join(__dirname,'file.config'))
.then(validateSettings);
The reason is that the validateSettings needs to be referenced as a function and the .then will invoke that function with the correct parameter. Doing it the way you are doing it, you receive a reference error because parsedData is not available at the time the function call is bound.

Node-soap client and scope of the callback

I'm using the node-soap client from milewise (create API by the way), but I have some difficulties to get the results of the callback to the right scope.
Here is the code I have for now:
function generateSoapRequest(req, res, next)
{
soap.createClient('http://127.0.0.1:' + cfg.service_port + cfg.service_url_path,
function(err, client) {
client.CXIf.CXIf.CXProcessXML(
{"XMLRequestData": {"CXLogon": {"UserID":"1901007", "Password":"2580", "LogonType":11 } } },
function(err, result, body) {
if (err) {
console.log(err);
return;
}
console.log(result);
var cxresponse = result.XMLResponse[0].CXResponse;
console.log('SessionID:' + cxresponse.SessionID + ' SessionInstanceID:' + cxresponse.SessionInstanceID);
});
});
}
function getVoiceMailInformation(req, res, next) {
var cxresponse = generateSoapRequest(req, res, next);
var something = doSomethingNext(cxresponse);
}
function doSomethingNext(cxresponse){....; return something;}
Basically, when I launch the getVoiceMailInformation(), it creates a soap client and request some information through the generateSoapRequest().
The next step would be to get the result of that function (not implemented in the code above, because I don't know how) and do something else.
My problem is soap.createClient is asynchronous, so the callback is fired well after the function is complete.
What would be the best approach ?
(Maybe it's something trivial, but the scope of an anonymous function in javascript is something that is killing me.)
Any help will be very appreciated.
Basically you can't do something like:
var cxresponse = generateSoapRequest(req, res, next);
because the function you're calling invokes asynchronous code, and therefore can't return a value that's determined by that code. The normal way around this is to give the function an extra callback parameter for a function that will be called with the result once the result becomes available. It doesn't have to be an anonymous function; it can be a named function. In your case, (assuming you've modified generateSoapRequest to take a callback as its fourth argument and call it when the results are ready, you could write
generateSoapRequest(req, res, next, doSomethingNext);
and then doSomethingNext will be called with cxresponse as an argument. Of course, since doSomethingNext also gets called asynchronously, it can't return a value either, so you'll have to apply the same technique to it.
The async module can make this sort of thing easier: in particular, its "waterfall" pattern is useful when you have a bunch of functions that have to run in sequence, each being called back from the previous one.

Resources