nodejs: wait for other methods to finish before executing - javascript

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();

Related

Promise in promise?

Is there any way I can make the following work:
function A
This function returns a promise that does a task which uses multiple webworkers, once the webworkers have collectively finished this task it will resolve the promise.
function B
This function executes function A, and after that it executes multiple other functions that require A to have been done first.
function C
This function executes function B, and after that it executes multiple other functions that require A. This function may onle be called once, as it is a single process which improves a certain genetic algorithm task by executing function B multiple times sequentially. (so no callback B -> C).
Something like this:
var someObject = {test: null};
function A () {
return new Promise((resolve, reject) => {
// do some task which requires webworkers
someObject.test = 10;
});
}
async function B(){
await A();
someObject.test *= 4;
return someObject.test;
}
function C(){
// set up complicated options here
// a loop using these options
var i = 100;
while(i--){
var x = B();
console.log(x);
// do tasks that require B;
}
}
C();
View it here on JSFiddle, please note that I want to avoid any kind of callbacks because I am already working with a complicated object architecture (i'm doing neuro-evolution).
The best thing I could think of is somehow wrapping function B in a promise as well, but I haven't figured out how to do that.
You can as well call await on async functions as they implicitly return a promise:
var someObject = {test: null};
function A () {
return new Promise((resolve, reject) => {
// do some task which requires webworkers
someObject.test = 10;
setTimeout(resolve, 1000);
});
}
async function B(){
await A();
someObject.test *= 4;
return someObject.test;
}
async function C(){
// set up complicated options here
// a loop using these options
var i = 100;
while(i--){
var x = await B();
console.log(x);
// do tasks that require B;
}
}
C();
You could return a promise from B(). Note, you don't need to resolve someObject in B() (i.e. resolve(someObject.test)) because it's a global var, but I did in order to demonstrate how to resolve a value and to follow your example code. Also note I removed the loop for example sake.
EDIT - thanks to #t.niese and others for pointing out the anti-pattern in my original answer. Please see the updated answer, below
https://jsfiddle.net/ey07zy6h/9/
var someObject = {test: null};
function A () {
console.log('in a')
return new Promise((resolve, reject) => {
// do some task which requires webworkers
someObject.test = 10;
resolve()
});
}
function B() {
console.log('in b')
return A()
.then(() => new Promise((resolve, reject) => {
someObject.test *= 4;
resolve(someObject.test);
}))
.catch(e => {
console.log('Err in A: ' + e)
})
}
function C() {
// set up complicated options here
console.log('in c')
// a loop using these options
var i = 100;
// while(i--) {
B()
.then(data => {
let x = data;
console.log('X is: ' + JSON.stringify(x));
// do tasks that require B;
})
.catch(e => {
console.log('Err in B', e)
})
// }
}
C();

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

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

make setTimeout as generic function and exec timeout

I have 3 functions, assume they are function a, b and c. All of them require a delay to start in different scope.
I can do in different places and event like this
setTimeout(function()a()},100);
setTimeout(function()b()},100);
setTimeout(function()c()},100);
but how can I make it cleaner?
This is exactly what ES6 Promises were made for.
function a() { console.log('a') }
function b() { console.log('b') }
function c() { console.log('c') }
function foo() {
return new Promise((resolve, reject) => {
setTimeout(function () {
resolve();
}, 100);
});
}
foo()
.then(a)
.then(b)
.then(c)
I understand this example is a little vague. But if you understand promises you can adapt it pretty well to your problem (and if you are not familiar with promises you can master Promises in a matter of hours).
You could also use Observables from Rjrx. The "fromInterval" operator is what you are looking for. Observables might be part of ES7.
You can try this approach.
function a() {
console.log("function a");
}
function b() {
console.log("function b");
}
function c() {
console.log("function c");
}
function callFunction(ref) {
setTimeout(function(){
ref();
},5000);
}
callFunction(a);
callFunction(b);
callFunction(c);
/* These are anonymous function. These will never wait for each other ro execute.*/
setTimeout(function(){a();},5000);
setTimeout(function(){b();},5000);
setTimeout(function(){c();},5000);
Before we start, as its common misconception, you must know that setTimeout time passed doesn't mean it will be executed exactly after 100ms. It can be longer (just not earlier). You should definitly watch a great talk by Philip Roberts - What the heck is the event loop anyway?.
Edit - as my answer covers setTimeout-way I think the answer given by #Adam Kettani is what you need, as with promises you can be sure the code will be executed in the right time and order, and it is also more clean what is going on.
Okay, let's get down to business. You can put them in array and then use a `forEach
const functions = [
function (){
console.log('a');
},
function (){
console.log('b');
},
function (){
console.log('c');
},
];
functions.forEach(fn => setTimeout(fn, 1000));
Keep in mind that they all will be set with timeout 1000ms, so they will most likely execute at the same time. If you want to have a delay in-between too just modify forEach:
const functions = [
function (){
console.log('a');
},
function (){
console.log('b');
},
function (){
console.log('c');
},
];
functions.forEach((fn, index) => setTimeout(fn, index * 2000));
To make this generic you can extract this line of code to a function:
const functions = [
function (){
console.log('a');
},
function (){
console.log('b');
},
function (){
console.log('c');
},
];
function _setTimeout (fn, delay) {
// setTimeout returns a value that allows you to
// cancel timeout, so it would be great if our function
// has this feature of converting array of functions
// to array of timeout ids
return fn.reduce((timeoutIds, fn, index) => {
return [...timeoutIds, setTimeout(fn, index * delay)];
}, []);
}
const timeouts = _setTimeout(functions, 2000);
console.log(timeouts);
clearTimeout(timeouts[2]);
console.log('C shall not pass!');

How to do a "for" loop with asynchronous condition in Javascript?

I have this function:
waitForFreeAccnt.prototype.isMemberFree = function () {
var self = this;
self.api.getMemberInfo(function () {
var accType = self.api.connect.accountType;
console.log(accType);
if (accType === 'FREE') {
console.log('it is free');
return true;
} else {
console.log('it is not free');
return false;
}
});
};
I would like to wait till the account is free for up to 10 seconds with something like that:
var test = function () {
for (var start = 1; start < 10; start++) {
var result = self.isMemberFree();
console.log(result);
if (result) {
break;
} else {
self.api.pause(1000);
console.log('waiting');
}
}
};
But it doesn't work because self.api.getMemberInfo is asynch call. This is super frustrating with Javascript. Any other language it would be so simple to do. How do I force the for loop to wait for self.isMemberFree() to finish executing before proceeding with the loop?
Also to note, this is not in browser execution so I don't care about anything hanging.
When dealing with asynchronous code, you need to make use of callbacks. That is, if you want to do a() and b() in order but a() does something asynchronously, then you need to call b() from within a() once a() has a result. So not:
a(); // does something asynchronously
b(); // tries to use a()'s result but it isn't available yet
... but rather
a(b); // pass b to a() and a() will call it when ready
function a(callback) {
triggerAsyncFunction(function(result) {
if (result === something)
callback("a just finished");
});
}
Note that a() doesn't refer to b() by name, it just calls whatever function is passed in as an argument.
So applying that to your code, maybe something like this:
waitForFreeAccnt.prototype.isMemberFree = function (cbf) {
var self = this;
self.api.getMemberInfo(function () {
cbf(self.api.connect.accountType === 'FREE');
});
};
waitForFreeAccnt.prototype.testMemberXTimes = function(maxAttempts, callback) {
var attempts = 0;
var self = this;
(function attempt() {
self.isMemberFree(function(free) {
if (free)
callback(true);
else if (++attempts < maxAttempts)
setTimeout(attempt, 1000);
else
callback(false);
});
)();
};
this.testMemberXTimes(10, function(isFree) {
// the next part of your code here, or called from here
// because at this point we know we've tested up to
// ten times and isFree tells us the result
});
Note that the way I coded getMemberInfo() it is basically doing the same thing yours was, but instead of returning a boolean it is calling the callback function and passing the same boolean value that you were returning. (I've removed the console.log()s to make the code shorter.)
Note also that you could structure the above to use promises, but the end result will be the same.
You could return a Promise
waitForFreeAccnt.prototype.isMemberFree = function () {
return new Promise((reject, resolve)=>
// set a timeout if api call takes too long
var timeout = setTimeout(()=> reject(Error('API timeout')), 10000);
// make api call
this.api.getMemberInfo(()=> {
clearTimeout(timeout);
resolve(this.api.connect.accountType === 'FREE');
});
);
};
Then use it like this
whatever.isMemberFree().then(isFree=> {
if (isFree)
console.log('it is free');
else
console.log('it is not free');
})
// handle timeout or other errors
.catch(err=> {
console.log(err.message);
});
Building on naomik's answer, if you do it that way you can pretty easily use a for loop with it, using the (most likely) upcoming async/await feature - though it's not part of ES2015.
// Note "async" here! That will make "await" work. It makes the function
// return a promise, which you'll be able to either "await" or
// "test().then" later.
var test = async function () {
for (var start = 1; start < 10; start++) {
// Right here we're using "await" - it makes JavaScript *wait* for
// the promise that comes from self.isMemberFree() to be finished.
// It's really handy because you can use it in loops like "for" and
// "while" without changing the flow of your program!
var result = await self.isMemberFree();
console.log(result);
if (result) {
break;
} else {
self.api.pause(1000);
console.log('waiting');
}
}
};
For now you'll need to use a transpiler like Babel or Traceur before you can really use async/await, though. It's only supported in Microsoft Edge 14 right now.
And a big emphasis that what is returned from test() isn't whatever you directly return from inside it. If I do this:
var test = async function() { return 15; };
var result = test();
I'm not going to get 15 - I'll get a promise that will resolve as 15:
result.then(function(res) {
console.log(res); // 15
});
// or, use an async function again:
var main = async function() {
console.log(await res); // 15
};
main();
I don't have my work laptop today because it is Sunday, I'm coding this on sublime. Apologise if the syntax is a bit off.
To solve your problem I would recommend changing isMemberFree() to take in a callback function. This is because isMemberFree is async, and you will need a way to report the result after it has done the work.
Then change test function to use setTimeout API to wait a second.
Wrap the function call for isMemberFree() to be in a nested function and call it recursively, that way you'll have synchronize control over the async calls.
Look at the coding example:
waitForFreeAccnt.prototype.isMemberFree = function (done) {
var self = this;
self.api.getMemberInfo(function () {
var accType = self.api.connect.accountType;
console.log(accType);
if (accType === 'FREE') {
console.log('it is free');
return done(null, true);
} else {
console.log('it is not free');
return done(null, false);
}
});
};
var test = function () {
var testMembership = function(waitAttempt, isFree) {
if (isFree) {
return;
}
else if (waitAttempt > 10) {
// wait exceeded, do something.
return;
}
setTimeout(function() {
self.isMemberFree(function(err, isFree) {
testMembership(waitAttempt+=1, isFree);
});
}, /*total milliseconds in 1sec=*/1000);
}
testMembership(/*WaitAttempts=*/0, /*isFree=*/false);
};
What the above code does is that, presumably something has already been done to the member's account and now test function is called. So it waits for 1 second, then call isMemberFree function, this happens recursively until either isMemberFree() returns true OR the 10 seconds wait has been exceeded.

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.

Categories

Resources