Callbacks in javascript (parameter passing) - javascript

I have had trouble understanding the rules concerning callbacks in javascript. I understand that callbacks run after function x finishes however I find there is ambiguity when defining them.
In the node.js docs : https://nodejs.org/en/knowledge/getting-started/control-flow/what-are-callbacks/
The code
function processData () {
var data = fetchData ();
data += 1;
return data;
}
is changed to
function processData (callback) {
fetchData(function (err, data) {
if (err) {
console.log("An error has occurred. Abort everything!");
return callback(err);
}
data += 1;
callback(data);
});
}
when the anonymous function is created why can we use parameters, where do these arguments come from, what rules regard these parameters?
The context of this question comes from the sockets.io library
Specifically:
var io = socket(server);
io.on('connection', function(socket){}
Why can we reference the socket, can I just add in function(random_param, socket)? What tells the function to reference when passing random_param?
I was told read the docs, which I had already done but that didn't make things any clearer.
Thanks in advance.

I understand that callbacks run after function x finishes...
Not necessarily. The JavaScript standard library (and various others) have lots of non-asynchronous callbacks. Think of the callbacks on the array functions forEach, map, sort...
...when the anonymous function is created why can we use parameters, where do these arguments come from, what rules regard these parameters?
They come from the code calling the callback. In your case, code in the socket.io library you're using calls the callback with two arguments, which your callback receives in the parameters err and data.
Here's a somewhat silly example: A function that calls a callback with a random number:
// This is analogous to the code in the socket.io library
function getARandomNumberWithRandomDelay(callback) {
setTimeout(() => {
callback(Math.random());
}, Math.random() * 1000);
}
// This is analogous to your code using the socket.io library
getARandomNumberWithRandomDelay(function(num) {
console.log("I got the number " + num);
});

Related

JavaScript Callback Functions.. confused

I'm sure the answer to this question exists somewhere, but unsure how to phrase the question and don't find what I'm looking for when I try to research callbacks.
Ok, so I've just started dabbling with Gulp for compiling my CSS, and I think it's great!.. despite being useless with JavaScript.
My code is below, but I don't understand how these callbacks are working. How can callbacks be set as a parameter and then be called from inside the function? I don't get it.. is the function basically expecting something to be in there? What value is being set or what's expected to run? I can't seem to make sense of it.
I see this quite frequently in JavaScript, but unsure how it works. I've looked up videos and tutorials of functions and callbacks, they makes sense, but I never seem to be able to find anywhere where this concept is explained which makes me believe I'm not looking for the right thing.
I see the same sort of thing with Promises as well where 'resolve' or 'reject' parameters are set, but unsure what's going on when a condition is met, or what values are set and where.. hope this makes sense and appreciate any help in understanding this better.
const gulp = require('gulp');
const sass = require('gulp-sass');
const browserSync = require('browser-sync');
// TASKS
// Compile SASS
gulp.task('sass-compile', (callback) => {
gulp.src('scss/*.scss')
.pipe(sass().on('error', sass.logError))
.pipe(gulp.dest('css'))
.pipe(browserSync.stream());
console.log('******************** SCSS > CSS successful ********************');
callback();
});
// Live reload
gulp.task('browser-sync', (callback) => {
browserSync.init({
proxy: 'http://localhost/test1',
port: 80
});
callback();
});
// WATCHER
gulp.task('default', gulp.series('browser-sync', (callback) => {
gulp.watch('scss/*.scss', gulp.series('sass-compile'));
callback();
}));
function foo(baz) {
console.log("Foo: " + baz);
}
function other(bar) {
const arg = "Bar";
bar(arg);
}
other(foo);
I can see how this is useful when it comes to performing asynchronous tasks. But its quite counter intuitive and I can immediately see the potential for type errors.
I've since changed my coding style to use ASYNC/AWAIT instead as much as possible. But it still a pain to navigate legacy code. Hence, the reason why I ended up looking up this thread. Haha
Functions are a type of object. Objects are a type of value.
Values can be stored in variables, in object properties, and passed as arguments to functions.
So:
Here is a simple function, which is called.
function foo() {
console.log("Foo");
}
foo();
Here is a simple function, copied to a different variable, which is called.
function foo() {
console.log("Foo");
}
const bar = foo;
bar();
And now passed as an argument to another function.
function foo() {
console.log("Foo");
}
function other(bar) {
bar();
}
other(foo);
And the same, but with arguments passed to the original function.
function foo(baz) {
console.log("Foo: " + baz);
}
function other(bar) {
const arg = "Bar";
bar(arg);
}
other(foo);
You've just been looking at examples where the function responsible for calling the callback is not code you've written (and you aren't looking at the source code of the function which calls the callback).
In javascript, functions are first class objects, which means they can be passed around to other functions. There are many cases where this can be used, but the cases you're referring to (gulp.task and new Promise) are essentially using it to do two-way communication between your code and their code. When you use gulp.task, basically the following steps are happening
1) You call gulp.task, saying "i'd like to do some work please". You pass in a function saying what you'd like to do
2) at the appropriate time, gulp.task calls your function, but passes in to it another function saying "when you're done, call this to let me know".
A simplified version of gulp.task would look like this:
const task = (name, workToDo) => {
const done = () => {
console.log('task', name, 'has let me know its done');
}
console.log('ive been asked to start task', name);
setTimeout(() => {
console.log('500ms elapsed; starting task', name);
workToDo(done);
}, 500);
}
task('sample', (done) => {
console.log('doing work');
setTimeout(() => {
console.log('1 second has elapsed. calling back to let it know i am done');
done();
}, 1000)
});
The constructor for a promise has a similar purpose. You say "i'd like to create a promise, using the following code", and then it calls your code passing in two functions that it just created (usually named resolve and reject). These are used to tell the promise "i'm done successfully" or "i'm done with an error", and thus move the promise to a resolved state or a rejected state.

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).

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