Node.js: Asynchronous Callback Execution. Is this Zalgo? - javascript

Executing the below using node - 6.0.
function A(callback) {
console.log('A');
callback();
}
function B() {
console.log('B')
}
function C() {
console.log('C');
}
A(C);
B();
// Result is A,C,B i expected that A, B, C
But changing the above example to use process.nextTick() prints A, B, C
function A(callback) {
console.log('A');
process.nextTick(() => {
callback();
});
}
function B() {
console.log('B')
}
function C() {
console.log('C');
}
A(C);
B();
Is this what we call as zalgo ? Can anyone provide me a realtime example of this, which will cause major breakdown ?

No, neither of these is zalgo. Your first A function always calls its callback synchronously, and should be documented as such. Your second A function always calls its callback asynchronously, and should be documented as such. Nothing is wrong with that, we use thousands of these every day. The outputs A C B and A B C are deterministic.
Zalgo refers to the uncertainty whether a callback is asynchronous or not.
function A(callback) {
console.log('A');
if (Math.random() < 0.5) {
callback();
} else {
process.nextTick(callback);
}
}
The output of the invocation A(C); B(); would be totally unpredictable.

First let me explain how the code works - see the comments in the code that I added:
// first you define function A and nothing happens:
function A(callback) {
console.log('A');
callback();
}
// then you define function B and nothing happens:
function B() {
console.log('B')
}
// then you define function C and nothing happens:
function C() {
console.log('C');
}
// now you call function A with argument C:
A(C);
// when A runs it prints 'A' and calls C before it returns
// now the C runs, prints C and returns - back to A
// A now has nothing more to do and returns
// Now the execution continues and B can be run:
B();
// B runs and prints 'B'
This is exactly the same as it would be in any language like Java, C etc.
Now, the second example:
// first you define function A and nothing happens:
function A(callback) {
console.log('A');
process.nextTick(() => {
callback();
});
}
// then you define function B and nothing happens:
function B() {
console.log('B')
}
// then you define function C and nothing happens:
function C() {
console.log('C');
}
// Then you run A with C passed as an argument:
A(C);
// A prints 'A' and schedules running an anonymous function:
// () => { callback(); }
// on the next tick of the event loop, before I/O events are handled
// but after the current code stack is unrolled
// then it returns
// And then B is run:
B();
// B prints 'B' and returns
// Now nothing else is left to do so the next tick of the event loop starts
// There's one function to run, scheduled earlier so it runs.
// This function runs the `callback()` which was `C`
// so C starts, prints 'C' and returns
// The anonymous function has nothing else to do and returns
// There is no more things on the event loop so the program exits
Update
Thanks to Bergi for explaining what is Zalgo in his answer. Now I better understand your concerns.
Is this what we call as zalgo ? Can anyone provide me a realtime example of this, which will cause major breakdown ?
I've seen a lot of code like this:
function x(argument, callback) {
if (!argument) {
return callback(new Error('Bad argument'));
}
runSomeAsyncFunction(argument, (error, result) => {
if (error) {
return callback(new Error('Error in async function'));
}
callback({data: result});
});
}
Now, the callback can be either run immediately before x() returns if there are bad arguments, or after the x() returns otherwise. This code is very common. For testing the arguments one could argue that it should throw an exception but let's ignore that for a moment, there may be some better examples of operational errors that are known immediately - this is just a simple example.
Now, if it was written like this:
function x(argument, callback) {
if (!argument) {
return process.nextTick(callback, new Error('Bad argument'));
}
runSomeAsyncFunction(argument, (error, result) => {
if (error) {
return callback(new Error('Error in async function'));
}
callback({data: result});
});
}
it would be guaranteed that the callback will never be invoked before x() returns.
Now, if that can cause a "major breakdown" depends entirely on how it is used. If you run something like this:
let a;
x('arg', (err, result) => {
// assume that 'a' has a value
console.log(a.value);
});
// assign a value to 'a' here:
a = {value: 10};
then it will sometimes crash with the version of x() without process.nextTick and will never crash with the version of x() with process.nextTick().

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

How to call 3 or 4 callback functions

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.

Chain multiple AJAX calls with delay and passing variables

I'm working on a way to chain a set of 3 ajax calls per variable against an array of data with some delay in between.
Taking into account this answer.
I'm trying to update the code to achieve the following:
Add a delay in the b() and c() function
Pass a variable from a() to b() and from b() to c()
Is there a way I can pass a variable a() would generate to b() without using global variables? If not that's fine, I'd just like to know.
And how exactly can I get b() to be delayed for several seconds before processing c()? I would assume adding in a setTimeout would work as it's waiting for the promise before it starts c(), but this is not the case.
jsfiddle
function a(user, pass) {
return $.post('/echo/json/', {}, function(re){
console.log(1);
});
}
function b() {
setTimeout(function() {
return $.post('/echo/json/', {}, function(re){
console.log(2);
});
}, 3000);
}
function c() {
console.log(3);
}
var data = [{u: 'au', p: 'ap'}, {u: 'bu', p: 'bp'}];
var counter = 0;
function main() {
if(counter < data.length) {
$.when(a(data[counter].u, data[counter].p).then(b).then(c)).done(function(){
counter++;
main();
})
}
}
main();
To ensure that c() isn't executed until after the timeout code has been called, create your own promise and return it from the b() function. You should wrap the setTimeout function in this promise, and call the resolve(res) method to notify the .then() functions watching the promise, passing an object representing the data or body of the response.
function b(dataFromA) {
return new Promise((resolve, reject) => {
setTimeout(function() {
return $.post('/echo/json/', {}, res => {
let dataToB = res;
console.log(2);
resolve(dataToB);
});
}, 3000);
});
}
Note that b() now accepts data that can be passed from the response of the a() promise. You can manipulate this data inside the b(res) function or in the promiseFromA.then(res => { // ... Your promise callback code }); before calling b(res).
setTimeout as used in function b is not a promise. i will find some docs to site and post shortly but here is what i see.
to use a promise you need to call a promise method, setTimeout is not a promise. it is only a delay. it has to do with the event loop in javascript or in the javascript runtime to be more correct. there is some good stuff over here --> https://github.com/getify/You-Dont-Know-JS/tree/master/async%20%26%20performance
also .then only works to resolve a promise
getify really breaks it down but i would start with the javascript event loop

Calling a function after another function's callbacks are returned

This is the simplified version of my problem:
var callback_one = function (result_from_web_service) {
console.log('callback one');
};
var callback_two = function (result_from_web_service) {
console.log('callback two');
};
// the async_calls are library calls that i don't own or modify
var x = function () {
console.log('x is called');
async_call_one(callback_one);
async_call_two(callback_two);
};
var y = function () {
console.log('y is called');
};
Test:
x();
y();
// prints: 'x is called', 'y is called', 'callback one', 'callback two'
// what i need: 'x is called', 'callback one', 'callback two', 'y is called'
What I did to accomplish this was calling y() inside call_back_two:
var callback_two = function (result_from_web_service) {
console.log('callback two');
y();
};
But now my use case requires that y be called outside of the callback (will be called by the user of my code). i.e. the calling of x() and y() be independent in a way that the calling of x() doesn't end up calling y(). y() should be called independently but only if x() and its callbacks are processed. think of x() as like creating an object in java and y() as a method you would call whenever you want.
//.. some code, x() does some kind of initialization...
x();
// OPTIONALLY call y(), but make sure x() and its callbacks are processed
y();
I tried the below but doesn't work.
$.when(x()).then(y());
Thanks,
The only way to make something like this work properly is to make y asynchronous. Basically, y internally waits for x to complete before executing its own code. This is similar to things like domready or onload which waits for other things to happen before executing their own logic.
There are two ways to accomplish this. The first, simplest and most naive way is setTimeout polling. Make x set a variable or attribute and check that before executing:
function y () {
if (x.ready) {
/* do what you need to do here */
}
else {
setTimeout(y,100);
}
}
The second method is to create virtual events or promises. Not all promise libraries support using a promise that has already expired (my own homemade one does) so you may need to write your own control flow to handle that case. For this you need to rewrite x to support an event or promise-like api:
var x = (function () {
var async_calls = 2;
var callback;
f = function () {
console.log('x is called');
async_call_one(function(){
async_calls --;
if (async_calls == 0 && callback) callback();
callback_one();
});
async_call_two(function(){
async_calls --;
if (async_calls == 0 && callback) callback();
callback_two();
});
}
f.loaded = function (loaded_callback) {
callback = loaded_callback;
if (async_calls == 0) callback();
}
return f;
})();
Now in y you can use the x.loaded function to execute your code when x is loaded:
function y () {
x.loaded(function(){
/* do what you need to do here */
});
}
Of course, this has the problem of making y asynchronous. Therefore if your users expect to write something like:
y();
a();
b();
then a and b may or may not execute before y. To solve this you need to make y accept a callback so that you users can control their program flow:
function y (callback) {
if (x.ready) {
/* do what you need to do here */
callback();
}
else {
setTimeout(function(){y(callback)},100);
}
}
or:
function y (callback) {
x.loaded(function(){
/* do what you need to do here */
callback();
});
}
So they'd have to use y like this:
y(function(){
a();
b();
});
Alternatively you can make y return a promise if you prefer that style.
A little bit down the road to spaghetti code but you could wrap up the two callbacks together by setting variables they both can see and only call y() when they both return.
for example
var finished = false;
var aync_call_one = function () {
//stuff
if (finished) {
y();
} else {
finished = true;
}
}
var aync_call_two = function () {
//stuff
if (finished) {
y();
} else {
finished = true;
}
}
However if you have to use jquery promises, you need to return a promise object to use $.when,
var deferred = $.Deferred();
return deferred.promise();
and inside the asyncs you need to do
deferred.resolve();
though that would only work for one of your async calls so you would need another $.when inside the first function, so it can get sloppy quick.

nodejs: wait for other methods to finish before executing

say I have 2 methods:
function A(callback) { ... }
function B(callback) { ... }
I want to execute:
function C();
after both A and B are finished.
what we usually do is to put function C in the callback like:
A(function() {
B(function() {
C();
});
});
now if both A and B takes a long time, I don't want B to execute after A has been finished. instead I want to start them at the same time to enhance performance.
what I'm thinking is to implement something like a semaphore (not really a semaphore of course), it fires an event after both A and B are finished. so that I can call C from within the event.
what I want to know is, is there any library implemented the above function already? I believe I'm not the first one who wants to do it.
any help is appreciated.
To expand on my comment...
async is a commonly used asynchronous flow control library for Node.js.
Its async.parallel() would probably do well for this:
async.parallel([
function(done) {
A(function () {
done(null);
});
},
function(done) {
B(function () {
done(null);
});
}
], function (err) {
C();
});
It's possible that this can be shortened, but it depends on how each function interact with callbacks and whether they follow the common Node.js pattern of error-first callbacks:
async.parallel([A, B], C);
For the sake of completeness and as mentioned above, the same result can be achieved using an external object to hold completion state where both A() and B() check to see if the other has completed and if so, invokes C(). As in:
var results={};
function onComplete(){
if(results['A'] && results['B'] && !results['C']) {
C();
}
}
function A(){
// ...
results['A']=true;
onComplete();
}
function B(){
// ...
results['B']=true;
onComplete();
}
The results object can be replaced by adding a 'isComplete' flag to both A() and B(), as in:
function A(){
// ...
A.isComplete=true;
onComplete();
}
And modifying onComplete to check this new flag:
function onComplete(){
if(A.isComplete && ...
}
Or, the same using events:
var util=require('util'),
events=require('events'),
EventEmitter=events.EventEmitter;
function F(){
EventEmitter.call(this); // init ancestor
}
util.inherits(F,EventEmitter); // assign ancestor
F.prototype.A=function(){
var self=this;
console.log('running A()');
setTimeout(function(){ // simulate long running code - 5 seconds
F.prototype.A.isComplete=true;
self.emit('complete','A');
},5000);
};
F.prototype.B=function(){
var self=this;
console.log('running B()');
setTimeout(function(){ // simulate long running code - 3 seconds
F.prototype.B.isComplete=true;
self.emit('complete','B');
},3000);
};
F.prototype.C=function(){
console.log('running C()');
};
var f=new F;
f.on('complete',function(which){ // onComplete handler
console.log(which+'() is complete');
if(F.prototype.A.isComplete && F.prototype.B.isComplete){
f.C();
}
});
// start it up
f.A();
f.B();
which, when run, will produce:
>node example.js
running A()
running B()
B() is complete
A() is complete
running C()
>
async.parallel([
function(){ ... },
function(){ ... }
], callback);
from: https://github.com/caolan/async
so in your case:
async.parallel([funcA,funcB],funcC);
//function definitions
function funcA() {...}
function funcB() {...}
function funcC() {...}
without modules i guess it would look something like this:
var numFuncs = 2;
A(D);
B(D);
and then
function D() {
if(numFuncs==0){ C(); } else {
numFuncs--;
}}
or like this:
A(D(C));
B(D(C));
function D() {
var x = process.funcsToCall= process.funcsToCall || {};
var f=arguments[0];
(!x.hasOwnProperty(f.name))?x[f.name]=0:x[f.name]++;
return function(){
(x[f.name]==0)?f():x[f.name]--;
}
}
If you're running on ES6, you can use Promise.all. Here is the example code rewritten:
Promise.all([
new Promise((resolve) => A(() => resolve())),
new Promise((resolve) => B(() => resolve())),
]).then(() => {
C()
}).catch(err => {
// handle errors from function A, B and C
})
we can aync and await for this purpose for example:
async function Foo(){
// function logic
}
and this Foo function as:
await Foo();

Categories

Resources