Node fibers/future callbacks with more than one argument - javascript

How does futures handle a callback that has more than one argument? This is critical to just about every use I could have for futures. The github example shows it only handleing one argument.
The example from the Github Readme is
var fileNames = readdir('.').wait();
But what about something a mysql call like
client.query("select * from employees", function(err, results, fields) {
// callback function returns employees array
callback(results);
});
How would I get those three (err, results, and fields) using the futures wait() method?
Edit
Experimentation has taught me that the first argument of the callback, in this case err, is always treated as an error and is thrown if the value is truthy. The second argument is assigned. Any further arguments are ignored as best as I can tell.

Create a wrapper for client.query, returning one data parameter with both results.
client.prototype.query2 = function ( sql, callback ) {
this.query(sql,
function(err, results, fields) {
var data={result:result, fields:fields};
callback(err,data);
}
};
I've recently created simpler abstraction than 'futures', also based on Fibers.
I haven't tested my code with a real world DB example yet. Please try it and help me test it if you can: https://github.com/luciotato/waitfor

Related

How to read javascript frameworks documentation?

Coming from the .NET world I am having a hard time consuming documentation for javascript frameworks. I will take "Node.js MongoDB Driver API" as an example. There is a Collection object which has the count() method. Here is the link for it: http://mongodb.github.io/node-mongodb-native/2.0/api/Collection.html#count
From there I see that count() takes three parameters:
count(query, options, callback)
At first I thought I need to provide all three of them in order to use this method. However, in the example code for this method I see that it sometimes uses only one and sometimes only one parameter:
// Perform a total count command
collection.count(function(err, count) {
test.equal(null, err);
test.equal(4, count);
// Peform a partial account where b=1
collection.count({b:1}, function(err, count) {
test.equal(null, err);
test.equal(1, count);
db.close();
});
In the first case it calls count() with only callback parameter while in the second it provides options and callback. There is no example of using all three parameters as stated in the original method description.
My question is how can one know these kind of things? I mean, if there were no examples in this documentation how would I know that would be possible? Also how can I be sure that there are some other possible usages of the method if that is not covered with examples like this?
I know it is perfectly legal to call javascript functions with only some parameters provided and function should be able to handle it based on the implementation. But as a consumer of API I don't want to look into function implementation to figure out what kind of parameter combination I can pass. It feels to me like this documentation is not complete (I took this mongodb driver just as an example but I came across to similar problem with other js framework docs).
Is there some kind of reasoning that I should have when reading javascript documentation, how to think about it when trying to understand API of different frameworks, how to know what is possible and what is not etc...?
In JavaScript and specially Node.JS world there is a common pattern on asynchronous functions that their last argument should be a callback function.
count(query, options, callback)
When you call a async function, you must foresee that the result of the call will come in a callback otherwise how could get the results of your async function call? so
based on the above statement you should at least provide a callback function to the count method and other async functions that you call in JavaScript.
Another thing that could help you when you see methods of MongoDB is that it is common that if you are going to process some data with the database, you need to provide at least a query object and a callback function but if you need additional information for your query you will provide, the options object.
I know that the documentation is not good explaining if the query and options parameters are optionals but if you see the source code of the count method and read my comments added on the code you could understand:
Collection.prototype.count = function(query, options, callback) {
// args represents the three parameters
var args = Array.prototype.slice.call(arguments, 0);
// extract your last argument and assumes that it is the callback function
callback = args.pop();
// extract the first argument that is query
query = args.length ? args.shift() || {} : {};
// extract the second argument but this time shift already extracted query
// so the first parameter this time will be options.
options = args.length ? args.shift() || {} : {};
...
}
if you pass the following values to the call, you will see the order commented in how the count method is going to grab the arguments:
count({}, {}, function callback() {}); // count(query, options, callback)
count({}, function callback() {}); // count(query, callback)
count(function callback() {}); // count(callback)
In fact in your example that you provided in the nested call to count method, you are passing a query and a callback and not options and a callback to the count method:
collection.count(function(err, count) {
test.equal(null, err);
test.equal(4, count);
// You are passing the values in this order (query, callback)
// {b: 1} === query
collection.count({b:1}, function(err, count) {
test.equal(null, err);
test.equal(1, count);
db.close();
});
I hope this explanation and code helps you to understand this common pattern of callbacks around JavaScript world.

NodeJS callback scope

As a js/node newcomer, I'm having some problems understanding how I can get around this issue.
Basically I have a list of objects that I would like to save to a MongoDB database if they don't already exist.
Here is some code:
var getDataHandler = function (err, resp, body) {
var data = JSON.parse(body);
for (var i=0; i < data.length; i++) {
var item = data[i];
models.Entry.findOne({id: item.id}, function(err, res) {
if (err) { }
else if (result === null) {
var entry = new models.Entry(item);
feedbackEntry.save(function(err, result) {
if (err) {}
});
}
});
}
}
The problem I have is that because it is asynchronous, once the new models.Entry(item) line is executed the value of item will be equal to the last element in the data array for every single callback.
What kind of pattern can I use to avoid this issue ?
Thanks.
Two kinds of patterns are available :
1) Callbacks. That is you go on calling functions from your functions by passing them as parameters. Callbacks are generally fine but, especially server side when dealing with database or other asynchronous resources, you fast end in "callback hell" and you may grow tired of looking for tricks to reduce the indentation levels of your code. And you may sometimes wonder how you really deal with exceptions. But callbacks are the basis : you must understand how to deal with that problem using callbacks.
2) Promises. Using promises you may have something like that (example from my related blog post) :
db.on(userId) // get a connection from the pool
.then(db.getUser) // use it to issue an asynchronous query
.then(function(user){ // then, with the result of the query
ui.showUser(user); // do something
}).finally(db.off); // and return the connection to the pool
Instead of passing the next function as callback, you just chain with then (in fact it's a little more complex, you have other functions, for example to deal with collections and parallel resolution or error catching in a clean way).
Regarding your scope problem with the variable evolving before the callback is called, the standard solution is this one :
for (var i=0; i<n; i++) {
(function(i){
// any function defined here (a callback) will use the value of i fixed when iterating
})(i);
});
This works because calling a function creates a scope and the callback you create in that scope retains a pointer to that scope where it will fetch i (that's called a closure).

How in Javascript (or in Node), the function's arguments are recognized?

I was learning Node.js (even though I am not an expert in Javascript but I understand and write code on it). Now, trying to play with Node.js, I just got stuck in this code:
var fs = require('fs');
fs.readFile('/etc/passwd', function (err, data) {
if (err) throw err;
console.log(data);
});
Here is some of my confusions:
The anonymous function is taking two arguments: err and data and inside the function err is for any error while reading the file which is thrown and data is the actual contents of the file.
Well, how the function knows and differentiate between which one is error and which one is content of the file?
Does it do like: the first argument is always an error and second argument is always the content data?
what err and data will have inside the function if I write like this
function(data, err) {} ?
This is just a simple function being passed just two arguments. How it works for some more arguments?
How inside the function, data is data and err is error?
For the above example, are err and data are pre-defined keywords (I doubt NO)?
The arguments will get values in the order they're passed while calling the function. You can see what's the correct order by reading the API docs for the function you plan to use.
So, if you change your function to function(data, err) {}, then data will contain the error, while err will hold the data :)
To ease your future work, nearly every Node.js function which accepts an callback, the 1st arg will be the error and the 2nd arg the return of the function.
1). Well, how the function knows and differentiate between which one is error and which one is content of the file?
The order of the arguments is known when the function is invoked from Node.
2). Does it do like: the first argument is always an error and second argument is always the content data?
Yes.
3). what err and data will have inside the function if I write like this
function(data, err) {} ?
They will have the same values, they simply won't be used.
For the above example, are err and data are pre-defined keywords?
Nope. You could even rename them and they will still be bound to the same values.
this is how it is defined in API
check here
as pointed by #gustavohenke if you define it like
function(data, err){ ... }
then data will hold error log and err will hold file data
EDIT
hope you read this in docs it should have cleared your doubt:
The callback is passed two arguments (err, data), where data is the contents of the file.

async.js - right method for probing

I have doubts on selecting async.js method for probing several alternatives and stop when the first of them is successful.
For example:
async.probeSeries([
function (callback) {
// try something and call callback
// without arguments - probing fails
callback();
},
function (callback) {
// try something and call callback
// with arguments - probing successful
callback(null, ok);
},
function (callback) {
// will be not executed, because
// the second one is successful
callback();
}
], function (err, result) {
// handle the result returned by the second probe
});
I think that using series and return the result as error way may be a workaround but is there a better way?
Maybe you are looking for detectSeries? It works a littlebit different than your example as it checks values from an array with the same function and then callbacks with one of these values, but maybe you can apply it to your problem.
Btw, this looks like the perfect use case for a promise library like Q, where you'd write
probe1().fail(probe2).fail(probe3).done(resulthandler, errhandler);

Join thread in JavaScript

Probably asked before, but after the serious searching I'm still not able to find a proper solution. Please consider something like this:
function compute() {
asyncCall(args, function(err, result) {
});
/* 'join thread here' */
}
Even though asyncCall is asynchronous I'd like to use the result and return it from the function compute synchronously. asyncCall is a library call and I can't modify it in any way.
How to wait properly for the asynchronous result without setTimeout and watching a conditional variable? This is possible but suboptimal.
not sure how you can really use something that doesn't exist yet, but it's easy enough to return a slot where the result will be:
function compute() {
var rez=[];
asyncCall(args, function(err, result) {
rez[0]=result;
if(rez.onchange){ rez.onchange(result); }
});
/* 'join thread here' */
return rez;
}
now, you can refer to the [0] property of the return, and once the callback comes in, compute()[0] will have the result. It will also fire an event handler you can attach to the returned array that will fire when the data updates inside the callback.
i would use something more formal like a promise or secondary callback, but that's me...
EDIT: how to integrate a callback upstream:
// sync (old and busted):
function render(){
var myView=compute();
mainDiv.innerHTML=myView;
}
//async using my re-modified compute():
function render(){
var that=compute();
that.onchange=function(e){ mainDiv.innerHTML=e; }
}
see how making it wait only added a single wrapper in the render function?
There's no await syntax in browsers that is widely available. Your options are generally limited to Callback patterns or Promises.
NodeJS follows a callback pattern for most async methods.
function someAsyncMethod(options, callback) {
//callback = function(error, data)
// when there is an error, it is the first parameter, otherwise use null
doSomethingAsync(function(){
callback(null, response);
});
}
....
someAsyncMethod({...}, function(err, data) {
if (err) return alert("OMG! FAilZ!");
// use data
});
Another common implementation is promises, such as jQuery's .ajax() method...
var px = $.ajax({...});
px.data(function(data, xhr, status){
//runs when data returns.
});
px.fail(function(err,xhr, status){
//runs when an error occurs
});
Promises are similar to events...
Of the two methods above, the callback syntax tends to be easier to implement and follow, but can lead to deeply nested callback trees, though you can use utility patterns, methods like async to overcome this.

Categories