How to call 3 or 4 callback functions - javascript

I need to understand how callback functions works.
I wrote this little script with 2 functions :
function fn1(callback) {
alert('fn1');
callback();
}
function fn2() {
alert('fn2');
}
fn1(fn2); //display 'fn1' then 'fn2'
Now, I want to update my script with a "fn3" function in order to display 'fn1' then 'fn2' then 'fn3'. I tried this :
function fn1(callback) {
alert('fn1');
callback();
}
function fn2(callback) {
alert('fn2');
callback();
}
function fn3() {
alert('fn3');
}
fn1(fn2(fn3));
but it dispay 'fn2', then 'fn3', then 'fn1', then log an error ("callback is not a function").
Any idea ? what's wrong ?
Thanks in advance, Florent.

In order to execute f1 then f2 then f3 you need to create a callback function in order to make sure a function will be executed in steps.
wrong:
fn1(fn2(fn3))) // this first call f2 with f3 as parameter then calls f1 with its result
right:
fn1(function () { // call f1
fn2(function () { // then call f2 after f1
fn3(); // then call f3 after f2
})
})

This sounds more like you're looking for promises
function fn1(){
return new Promise(resolve => {
alert("fn1");
resolve()
});
}
function fn2(){
return new Promise(resolve => {
alert("fn2");
resolve()
});
}
function fn3(){
return new Promise(resolve => {
alert("fn3");
resolve()
});
}
fn1().then(fn2).then(fn3);

fn3
You take the value fn3 which is a function.
fn2(fn3)
You pass that value as the argument to fn2, another function, which you call.
function fn2(callback) { alert('fn2'); callback(); }
You alert, then you call the argument (the function you got from fn3) as a function (I'll skip over the details of what it does) and then return undefined (since you have no return statement).
fn1(fn2(fn3));
Since fn2(fn3) returns undefined this is the same as fn1(undefined).
function fn1(callback) { alert('fn1'); callback(); }
You alert, then try to call undefined as a function, which it isn't, so it errors.
How to call 3 or 4 callback functions
Probably… rewrite the functions so they make use of Promises instead of plain old callbacks.
But there is no point in using callbacks for your example at all, and the best solution to a real problem will depend on what that problem is.

fn1(fn2(fn3))
Here we have a call to function fn1 with 1 argument which is return value of function fn2. This statement is evaluated so that fn2 is first called with its parameter fn3 and then the return value is passed to fn1. fn2 calls its parameter. This is why you get "unexpected" order of alerts.
fn2 does not return anything so that is why you get error from fn1.

Related

Why this callback is not running properly?

I'm a noob in coding. I'm really sorry about that. I have this code here....
function fn1(){
setTimeout(function(){console.log("fn1")},3000)
}
function fn2(){
console.log("fn2")
}
function fn3(callback, callback2){
if(callback){
console.log("It works!")
} else {
callback2
}
}
fn3(fn1(),fn2())
The objective here is to call Function3(fn3) console.log ("It works") only after Function1(fn1) runs ok. If Function1 fails, it should return Function2.
The output that I'm getting is:
fn2
fn1
I know it is extremely wrong but I don't know WHAT is wrong.
I know that there are other stuff (that I still don't know - like promises, async, await and stuff) but I wanna learn this method first.
Could you guys help me?
Yes, you are right. This is a huge nonsense.
Correct me if I'm wrong: you want the console to log "It works!" after the timeout set in the fn1. Then you'll need the fn1 to tell somehow that it finished it's execution so it can run the console.log. If you want to use the callback approach, then the fn1 could be something like:
function fn1(callback, errorCallback) {
setTimeout(function() {
try {
callback();
} catch (error) {
errorCallback();
}
}, 3000);
}
And the fn3 could go like this:
function fn3() {
fn1(function() { console.log('It works!'); }, fn2);
}
You can call fn3 just with fn3().
To be honest, as simple as these functions are, there's no way the fn2 is called as there are no errors in the code and no human interaction. Well, maybe if there's no standard output available to do the console.log, but I don't know if that's even possible.
As you can see, in the fn3 we are passing two functions as parameters to fn1. The first is an anonymous function that shows the text in the output. The second function is the fn2, that should be run in case of error. No parenthesis here when passing them as parameters as we want to pass functions, not the result of calling them (which would be undefined in this example).
The fn1 receives those functions as parameters and runs them in different situations. The first, when the timeout has finished, and the second if there's any error when calling the callback.
You have to pass references on the functions as parameters of fn3 (you currently call them and pass their result).
Also, in the fn3, you need to call the function.
Your code fixed below (if I correctly understood what you were looking for):
function fn1(next) {
setTimeout(next, 3000);
}
function fn2() {
console.log("fn2")
}
function fn3(callback, callback2){
function itWorks() {
console.log('it works!');
}
try {
callback(itWorks);
}
catch (e) {
callback2();
}
}
fn3(fn1, fn2); // Will display "it works!" after 3 seconds
fn3(undefined, fn2); // Will display "fn2" because trying to call an undefined function
I understood that you want to call f3 after the f1 is called successfully and call the f2 when f1 fails? If yes then see this
function fn3(){
console.log("It Works!");
}
function fn2(){
console.log("fn2");
}
function fn1(){
const promisePass = new Promise((resolve, reject) => {
setTimeout(resolve, 100)}); //Emulate success
const promiseFail = new Promise((resolve, reject) => {
setTimeout(reject, 100);});//Emulate fail
promisePass.then(function(){
fn3();
}).catch(function(){
fn2();
});
promiseFail.then(function(){
fn3();
}).catch(function(){
fn2();
});
}
fn1(); //<<-- calling f1 now will pass and fail the setTimeout method and then
// fn2 and fn3 are called accordingly

CallBack function execution in javascript?

function nestedFunction() {
console.log('nested function');
}
function firstFunction(cb) {
cb(nestedFunction());
}
function resetRouter() {
setTimeout(() => {
console.log('hello');
firstFunction(() => {
console.log('inside oye oyr');
});
}, 1000);
}
resetRouter();
This is my function . In this first reset Router is executed. Inside resetRouter after 1 second my first function is getting executed. First function takes a callback function as a param . Till here the things are clearer to me. But when the firstFunction is getting called it recieves a cb as a param , we are executing the callBackfunction and inside that callback function we are passing the nested function . So here first our nested function gets executed then the cb(callBack gets executed). So how is this being executed. Please someone explain its execution in a more clearer and easy way.
function firstFunction(cb) {
cb(nestedFunction());
}
You're not passing nestedFunction. You're passing the value resulting from invoking nestedFunction (see the () after it). If you just want to pass a reference to nestedFunction into cb, just pass the name.
function firstFunction(cb) {
cb(nestedFunction);
}
This is what happens:
1: resetRouter gets called.
2: In 1 second:
a. resetRouter logs "hello" in the console.
b. call `firstFunction` with the argment - () => console.log("inside oye oyr")
note: the callback function doesn't get executed in this step.
c. nestedFunction gets called.
d. nestedFunction logs "nested function"
e. the callback in `b` gets called with one argument - undefined
f. finally, `b` logs "inside oye oyr" in the console.
Output:
hello // from resetRouter
nested function // from nestedFunction
inside oye oyr // from firstFunction callback.

How to pass a callback function with multiple possible parameter lists

Here are two callback function:
function callback_a(){
alert('a');
}
function callback_b(p){
alert('b says'+ p)'
}
If I want use callback_a
function test(callback){
if(condition){
callback();
}
}
test(callback_a);
But the function test isn't applicable to callback_b, So how to implement a common function that you can passing some callbacks function with multiple possible parameter lists.
There are three options:
The easiest way is to use spread operator:
function test(callback, ...callback_args) {
callback(...callback_args);
}
in this case the invocation of test for function callback_b would be like this:
test(callback_b,"b")
The second way is using arguments which are scoped to any function in JavaScript:
function test(callback) {
callback.apply(null, arguments.slice(1));
}
the invocation of test for function callback_b would be the same:
test(callback_b,"b")
Another options is to use partially applied functions. In this case you should define b_callback like this (ES6 syntax):
let callback_b = (p) => () => void{
alert('b says'+ p)'
}
or without ES6:
function callback_b(p) {
return function(){
alert('b says'+ p)'
}
}
and invoke it like this:
test(callback_b("b"))
There is a special object called arguments that gets created when a function is invoked. It's an array-like object that represents the arguments passed in to a function:
It can be used like this:
test();
// no arguments passed, but it still gets created:
// arguments.length = 0
// arguments >> []
test(a);
// ONE argument passed:
// arguments.length = 1
// arguments >> [a]
test(a,b,c,d);
// FOUR arguments passed:
// arguments.length = 4
// arguments >> [a,b,c,d]
Knowing this, one can call a callback with the rest of the arguments passed in from the parent function using apply like this:
function test(callback) {
callback.apply(null, Array.prototype.slice.call(arguments, 1));
}
// arguments passed into test are available in the function scope when
// .slice is used here to only pass the portion of the arguments
// array relevant to the callback (i.e. any arguments minus the
// first argument which is the callback itself.)
//
// N.B. The arguments object isn't an array but an array like object so
// .slice isn't available on it directly, hence .call was used here)
Might be worth reading up on:
The arguments object
Function.prototype.apply, Function.prototype.call and Function.prototype.bind as they are way to bind a context and arguments to a function (i.e. they'll work with the arguments object to call a function where you may not know how many arguments will be passed)
So how to implement a common function that you can passing some callbacks function with multiple possible parameter lists.
Basically, you don't. The function receiving the callback is in charge of what the callback receives as arguments. When you call Array#forEach, it's Array#forEach that decides what arguments your callback gets. Similarly, String#replace defines what it will call its callback with.
Your job is to say what test will do, what it will call its callback with. Then it's the job of the person using test to write their callback appropriately. For instance: You might document test as calling the callback with no arguments. If the caller wants to use callback_b, then it's up to them to handle the fact that callback_b expects a parameter. There are several ways they can do that:
The could wrap it in another function:
test(function() {
callback_b("appropriate value here");
});
...or use Function#bind
test(callback_b.bind(null, "appropriate value here"));
...but it's their problem, not yours.
Side note: If they pass you callback_b and you call it without any arguments, you won't get an error. JavaScript allows you to call a function with fewer arguments than it expects, or more. How the function handles that is up to the author of the function.
You can pass an anonymous function as the callback that will itself return your desired callback function with parameters.
test(function() { return callback_b(' how are you'); });
see this working snippet that will first use callback_a, then callback_b (with parameter) as the callback:
function callback_a(){
alert('a');
}
function callback_b(p){
alert('b says'+ p);
}
function test(callback){
if(true){
callback();
}
}
test(callback_a);
test(function() { return callback_b(' how are you'); });
You can pass the parameter while calling the callback
function test(callback){
if(condition){
callback();
}
else if(other condition){
callback("b");
}
}
test(callback_b);
You can write your callback function like
function callback_a_b(){
if(arguments.length){
var arg = [].slice.call(arguments);
alert('b says'+ arg[0])
}
else{
alert('a');
}
}
You can pass array of parameters as second param of test function or in ES6 use spread operator read more here
function test(callback, params){
if(condition){
if (params === undefined){
callback();
} else {
callback.apply(null, params); //params must be array
//ES6: callback(...params);
}
}
}
test(callback_a);
test(callback_b, [" whatever"]);
I've just checked in my browser (ffox 51.0.1) that the following works:
function test(callback,other_args){if(condition){callback(other_args);}}
results:
condition=true
test(callback_a)
=> shows the alert with 'a'
condition=false
test(callback_a)
=> doesn't show anything
condition=true
test(callback_b,"pepe")
=> shows the alert with 'b sayspepe'
condition=false
test(callback_b,"pepe")
=> doesn't show anything

can we give a callback with parameters?

function abc(arg1,arg2, callback){
console.log(arg1 + arg2) // I am doing something really interesting
if(callback){
callback(arg1+ arg2)
}
}
function add(){
console.log("from call back " + arguments[0])
}
var a =10;
abc(1,2, add)
this works fine, but if we need to send some additional arguments to the call back, what should we do??
Here, Apart from (arg1+ arg2) I need some other arguments to be set from the caller of abc to the callback
And, what is the difference between abc(1,2,add) and abc(1,2,add()) ??
Thanks :)
abc(1,2,add) => Giving the function argument as "function type". This is like giving a pointer to the function for later invoking it.
abc(1,2,add()) => Calling the add() function and giving its return value as argument.
Do you need that the callback support more than an argument? Since JavaScript is a dynamic language, just call the same callback function with more arguments:
callback(1,2,3,4)
callback(1,2,3,4,5)
callback(1,2,3,4,5,6).
JavaScript isn't strict with function signatures: functions have as many arguments as the caller gives to them.
For example, if you've a callback function like this:
function(a, b) {
}
And later you call it this way:
function("hello"); // Where's the second argument??
JavaScript won't complain. Simply b will be undefined.
the difference between add and add():
add is a function and add() is the return value of the function.
if you want to get more arguments of the function. use the arguments object
every function has an arguments object
arguments[0] == 1 arguments[1] == 2 arguments[2] == add.
You can call your callback with parameters from your original function and you can also provide the parameters for the callback inside your function call:
function f1 (args, callback, params) {
callback.apply(this, params); // Params needs to be an array
callback.apply(this, [args]); // This would call callback with 1 param - args
callback.call(this, args); // This is the same as the line above
}
function f2 () {
for (item in arguments) {
console.log(item);
}
}
f1('arg', f2, [1, 2, 3]);
If you call your function with a function call inside the parameters then it would immediately evaluate and it would not be executed as a callback.
The difference between abc(1,2,add) and abc(1,2,add()) is that in the second case, it's not abc that calls add. The consequence is that add executes much sooner than expected and without any arguments.
The usual way to pass extra parameters to a callback is to create an anonymous function that closes over the parameters:
var a=10;
var b=20;
abc(a, b, function(text){
add(a, b);
console.log(text); //logs "abc"
});

Callback function - use of parentheses

I'm new to jQuery and am bit confused about the use (or not) of parentheses with a callback function. Say I have a function:
function cb() {
// do something
}
Now what is the difference between:
$("p").hide(1000, cb);
and
$("p").hide(1000, cb());
Is it to do with when the cb function is executed? It would be great if someone could explain this to me in the simplest of terms.
cb() means give me the result of executing the function cb.
cb IS the function cb or, more accurately a pointer (reference) to it.
Is it to do with when the cb function is executed?
Essentially, yes, though the difference does run a little deeper than that.
cb is a reference of sorts to the function. You're passing the function along as a parameter to be invoked somewhere down the line.
cb() is a function call; the function will be invoked, and the result passed as an argument to .hide.
The difference is that in javascript functions are first class objects and can be passed to other functions so that they may executed at a later stage or depending on some logic.
Consider the following:
function add(a, b) {
return a + b;
}
function minus(a, b) {
return a - b;
}
function apply(func, a, b) {
return func(a,b);
}
apply(add, 3, 4); // returns 7
apply(minus, 3, 4); // returns -1
apply(add(), 3, 4); // error: invalid number of arguments for add
apply(add(0,0), 3, 4); // error: add returns 0, but 0 is not a function and
// so apply crashes when it tried to call zero as a function
$("p").hide(1000, cb); passes the function referenced by cb, as a callback.
$("p").hide(1000, cb()); passes the value returned when the function cb is called.
Given:
function cb(){ return true; }
The former is passing the callback for later calling. The latter passes the returned value true, and is essentially $("p").hide(1000, true);

Categories

Resources