Chain of promises in javascript with ajax calls - javascript

I have a function (f1) which I want to get called only after two ajax calls (say a1 and a2) are done. a2 should be called only after a1 is done. Following is the sequence of operation =
$.when(a1 and a2) {
f1
}
I tried the following code snippet -
$.when(a1a2()).done(function(){
f1();
}
var a1a2 = function(){
return $.when(a1()).done(function() {
if (<check for a few variables a1 sets>) {
// another ajax call for which f1 should wait
return a2();
} else {
// random function for which f1 shouldn't wait
f2();
}
});
}
In the above code, f1 is waiting for a1 to finish but it is not waiting for a2 to finish.
I tried the following code snippet as well (but this also just waits for a1 to finish) -
var a1a2 = function(){
var retVal = new Promise(function(){
a1().then(function(){
if (<check for a few variables a1 sets>) {
return a2();
} else {
// random function for which f1 shouldn't wait
f2();
}
});
});
}
I have looked at other similar questions but an not able to devise a solution. Can someone please help?

First of all, your Promise code is faulty, because you're not creating a Promise correctly
new Promise(function(resolve, reject) {
// in here you call resolve or reject otherwise Promise is forever pending
});
However, since a1 returns a Promise (as do all the functions, I'm assuming) you don't need to create a promise
So, your code would be
a1()
.then(function() {
if (somecondition == true) {
return a2();
} else {
f2(); // since there's no return here, there's no "wait" for the promise f2 returns
}
})
.then(function() {
return f1();
})
To illustrate the above, here's your code once with condition true, and then with condition false
Take note of the "time stamps" for the console output
// dummy code to set up some promises
const dummy = (x, d=1000) => {
console.log(performance.now(), 'start', x);
return new Promise(resolve => setTimeout(() => {
console.log(performance.now(), 'end', x);
resolve(x);
}, d));
};
const a1 = () => dummy('a1');
const a2 = () => dummy('a2');
const f1 = () => dummy('f1');
const f2 = () => dummy('f2', 3000);
// end dummy code
console.log('wait for a2');
a1()
.then(function() {
if (true) {
return a2();
} else {
// random function for which f1 shouldn't wait
f2();
}
})
.then(function() {
return f1();
})
.then(() => {
console.log('dont wait for f2');
a1()
.then(function() {
if (false) {
return a2();
} else {
// random function for which f1 shouldn't wait
f2();
}
})
.then(function() {
f1();
});
});
However! If f2 is a function that has no asynchrony then there is no way * to prevent f1 from being called after f2 finish - because that's how javascript works
* - I guess you could put it in a setTimeout, then f2 would execute after f1 begins (again, assuming f1 has some asynchrony, otherwise f2 would begin after f1 ends)

Call a1 to get its Promise, then call Promise.all on a1 and a1 chained with a2:
const a1Prom = a1();
Promise.all([
a1Prom,
a1Prom.then(a2)
])
.then(f1);
console.log('script start');
const delay = ms => new Promise(res => setTimeout(res, ms));
const a1 = () => delay(1000).then(() => console.log('a1 done'));
const a2 = () => {
console.log('a2 starting');
return delay(1000).then(() => console.log('a2 done'));
};
const f1 = () => console.log('f1 starting');
const a1Prom = a1();
Promise.all([
a1Prom,
a1Prom.then(a2)
])
.then(f1);

I'm not familiar with the when/done syntax, but this is a correction for your second snippet. A big hint I would give is that using new Promise is 90% of the time a bad idea.
var a1a2 = function(){
var retVal = a1().then(function(){
if (<check for a few variables a1 sets>) {
return a2();
} else {
// random function for which f1 shouldn't wait
f2();
}
});
});

function a1() {
return new Promise(resolve => {
resolve();
});
}
function a2() {
return new Promise(resolve => {
resolve();
});
}
function f1() {
// this runs when the a1 and a2 is resolved.
}
// this is the call method. there are so many approach in your question first is chaining of promise.
function CallMethod(){
a1().then(function () { // you can optionally pass data here via the resolve in the promise
return a2();
}).then(function () { // same here you can pass optional data here.
// here the a1 and a2 is resolved you can call the f1() now.
f1();
});
}
// second one is called Promise.all()
function CallMethod() {
Promise.all([a1(), a2()]).then(data => { // this is the optional data passed in the resolve base on the index of the function promises.
var firstResolve = data[0]; // resolved data of a1();
var secondResolve = data[1]; // resolved data of a2();
})
}

Related

How can I chain functions asynchronously using JavaScript?

I was asked to create such an object called foo that can chain the function log and wait.
For example:
foo.log('breakfast').wait(3000).log('lunch').wait(3000).log('dinner');
In this scenario it prints breakfast first, waits 3 seconds, prints lunch, and then after 3 seconds it prints dinner.
I tried something like this, but it doesn't work. What did I miss?
var foo = {
log: function(text){
console.log(text);
return foo;
},
wait: function(time) {
setTimeout(function() {
return foo;
}, time);
}
}
foo.log('breakfast').wait(3000).log('lunch').wait(3000).log('dinner');
It's always better to use promises. An implementation of this functionality could be;
class Foo {
constructor(){
this.promise = Promise.resolve();
}
log(txt){
this.promise = this.promise.then(_ => console.log(txt))
return this;
}
wait(ms){
this.promise = this.promise.then(_ => new Promise(v => setTimeout(v,ms)));
return this;
}
}
var foo = new Foo();
foo.log("happy").wait(1000).log("new").wait(1000).log("year");
For the record, Redu's excellent answer without the class sugar.
See also
const foo = {
promise: Promise.resolve(),
log(txt) {
this.promise.then(_ => console.log(txt));
return this;
},
wait(ms) {
this.promise = this.promise.then(_ => new Promise(v => setTimeout(v, ms)));
return this;
}
};
// OR
const Foo = (defaultMs = 1000) => {
let promised = Promise.resolve();
return {
log(txt) {
promised.then(_ => console.log(txt));
return this;
},
wait: function(ms) {
promised = promised.then( _=>
new Promise( rs => setTimeout(rs, ms || defaultMs) ) );
return this;
}
};
};
foo.log("Happy").wait(1000).log("new").wait(1000).log("year");
Foo().wait(3000)
.log(`** From Foo ;)`).log(`Happy`).wait().log("new").wait().log("year");
Place the call to wait inside the previous one, and as the last item, like a recursive function.
meals=['breakfast','elevenses','lunch','afternoon tea','dinner','supper'];
c=0;
wait=t=>{setTimeout(function() {
if (c<meals.length) document.write(meals[c++],'<br>');wait(500);
}, t);}
wait(500);
I was inspired by #James 's solution, which is partially wrong because the log messages are in the reverse order, but he does not use Promises. I still think that #Redu 's solution should be the accepted one (after all if you can use Promises, that is perfect), but this one is interesting too in my opinion:
const foo1 = {
incrementalTimeout: 0,
nextActions: [],
log(text) {
const textLog = () => { console.log(text); };
if (this.incrementalTimeout == 0)
textLog();
else
this.nextActions.push(textLog);
return this;
},
wait(time) {
let newObj = {...this, incrementalTimeout: this.incrementalTimeout + time, nextActions: []};
setTimeout(() => { newObj.nextActions.forEach((action) => action()); } , newObj.incrementalTimeout);
return newObj;
}
}
foo1.log('breakfast').wait(1000).log('lunch').wait(3000).log('dinner');
The idea is that I do not immediately log text but I push a lambda with the console.log in an array that is going to be called after the correct timeout expires.
I run all the log and wait operations one after the other, but I keep track of the seconds to wait before executing the actions. Every time a new wait is called, the incrementalTimeout is increased by time. To keep the nextActions belonging to different time frames separated, I return a newObj every time, more or less like #James does.
Shorter, within Promise (not recommended).
Promise.prototype.log = function(txt) {
return this.then(() => console.log(txt))
}
Promise.prototype.wait = function(ms) {
return this.then(() => new Promise(res => setTimeout(res, ms)))
}
var foo = Promise.resolve()
foo.log('breakfast').wait(3000).log('lunch').wait(3000).log('dinner')
You can do it without promises:
const foo = {
log(text) {
return {...foo, start: () => {
this.start();
console.log(text);
}};
},
wait(time) {
return {...foo, start: () => {
setTimeout(this.start, time);
}};
},
start() {}
};
foo.log('breakfast').wait(3000).log('lunch').wait(3000).log('dinner').start();
The functions foo.log() and foo.wait() return immediately, returning a modified clone of foo. A clone is made using {...foo}, but with the start() function modified so that it calls the caller's this.start() followed by the new operation. When the chain is complete you call start() to start the actions.

How to call a different function after completion of one function?

I have written long code, trying to replicate the situation in simple form by this simple code.
What I want to do is after function A() completion, call function B().
I am trying with callback function but in this case, B fired early.
Please suggest how can I write this callback or any other approach?
function A(callback){
a()
function a() {
setTimeout(aa,1000)
function aa(){
console.log("in aa")
}
}
b()
function b() {
setTimeout(bb,100)
function bb(){
console.log("in bb")
}
}
c()
function c(){
setTimeout(cc,50)
function cc(){
console.log("in cc")
}
}
callback();
}
function B() {
console.log("in B");
}
A(B)
output
in B
in cc
in bb
in aa
If you want your callback to run after a timeout has finished, then you have to call it when the timeout has finished.
And that means it needs to be at the end of the function you pass to setTimeout.
With your current code, you are setting the countdown on the timeout going and then immediately calling the callback.
function one(callback) {
console.log(1);
function two() {
console.log(2);
callback();
}
setTimeout(two, 250);
}
function three() {
console.log(3);
}
one(three);
Essentially, what's happening here (as you requested) is that you want B to run after A is completed.
There is no need to use "B" as a callback, with async/await.
B will wait till A is completed before it's called.
const b = () => {
return new Promise((resolve, reject)=>{
setTimeout(()=>{resolve("B done")}, 1000);
});
}
const c = () => {
return new Promise((resolve, reject)=>{
setTimeout(()=>{resolve("C done")}, 500);
});
}
const A = async () => {
const bres = await b();
console.log(bres);
const cres = await c();
console.log(cres);
};
const B = async () => {
console.log("done");
}
const app = async() => {
await A();
await B();
};
app();

Create a function that no matter how many times invoked run only when first async call finishes?

suppose I've a function fetch(id).
I would be calling it arbitrarily at random times.
But I want every successive call to run only after previous call has finished.
say the async task takes 4 seconds, and i call fetch 3 times. then total time should be 12 seconds.
I could make a array and at every call set promise to go through next in line.
but what are some ways to accomplish this.
I think I got it
//First my example function which could be anything but should return promise which would be queued
function example(n) {
return new Promise((res, rej) => {
setTimeout(()=> {
console.log(n);
res();
}, 1000);
});
}
//now solution
function debounce(func) {
let p = Promise.resolve();
return function(x){
p = p.then(() => func(x));
}
}
//usage
d = debounce(example);
d(1);d(2);d(3);d(4);d(5);d(6);d(1);
You can chain Promises without an array, just store a pointer to the last Promise
// async payload function
// returns a promise
function f(x) {
console.log(`call f(${x})`);
return new Promise((resolve) => {
setTimeout(() => {
console.log(`resolve f(${x})`);
resolve();
}, 2000);
});
}
// wrapper to call function `f` sequentially
// stores pointer to the last Promise in closure
const g = (function(){
let lastPromise = Promise.resolve();
return function(arg){
lastPromise = lastPromise.then(() => f(arg));
}
})();
// generate random calls of function function `g`
for (let i = 0; i < 5; i++) {
setTimeout(() => g(i), Math.random() * 100);
}
I guess you can use async.io library.
Or, each time you want to call your function, push the function itself in an array. When the previous function has finished, check if there is still some functions to call in the array.

Observable wait for a method to complete

I want to run method A and B parallelly and once they both are done, I want to run method C.
How can I achieve this in javascript using Observable?
main() {
this.methodA();
if(some_condition) this.methodB();
this.methodC();
}
methodA() {
setTimeout( () => { console.log("doing some work A"); }, 500);
}
methodB() {
setTimeout( () => { console.log("doing some work B"); }, 250);
}
methodC() {
console.log("should be the last...");
}
expected output (if some_condition is false):
doing some work A
should be the last...
expected output (if some_condition is true):
doing some work A
doing some work B
should be the last...
expected output (if some_condition is true):
doing some work B
doing some work A
should be the last...
While I agree that it seems like your spec could probably best be accomplished using promises, I figured I'd give you an answer using Observables, seeing how that's what you asked for.
Essentially, just use the merge operator, make methodA() and methodB() return observables, and call methodC() when they're all complete:
var some_condition = true
function main() {
let test$ = a()
if (some_condition) test$ = test$.merge(b())
test$.subscribe(console.log, null, c)
}
function a() {
return Rx.Observable.timer(500)
.mapTo('doing some work A')
}
function b() {
return Rx.Observable.timer(250)
.mapTo('doing some work B')
}
function c() {
console.log('should be the last...')
}
main()
This logs:
doing some work B
doing some work A
should be the last...
Your best bet would be to use a Promise which allow functions to be run asynchronously and then trigger some function when they have completed. The benefit here is that promises can be composed so that you can wait on any or all of them to resolve before doing some work.
Use ES7s async functions / await :
async function main() {
await this.methodA();
if(true || some_condition) await this.methodB();
await this.methodC();
}
async function methodA() {
console.log("doing some work A");
await timer(1000);
console.log("finished A");
}
async function methodB() {
console.log("doing some work B");
await timer(1000);
console.log("finished B");
}
async function methodC() {
console.log("should be the last...");
}
function timer(time){
return new Promise(function(res){
setTimeout(res,time);
});
}
main();
People may forget the hidden gem of Observable.if().
Observable.if(condition, thenSource, [elseSource]) takes in 3 arguments. First argument is the boolean condition, second argument is an Observable to be emitted if condition is true, and the last one being an array of else source, that is to be emmitted if condition is false.
If you want to fully Observable-lised your code, you can do it this way:
1. Have all your methods return an Observable:
const methodA = () => {
return Observable
.timer(500)
.do(() => {
//do your work A here
console.log('doing some work A');
})
};
const methodB = () => {
return Observable
.timer(250)
.do(() => {
//do your work B here
console.log('doing some work B');
})
};
const methodC = () => {
console.log("should be the last...");
};
2. Use Observable.if() to resolve the streams
Now, in your main, simply use an Observable.if() to check if the condition is true, and emit the Observable accordingly:
const main = () => {
let some_condition = true;
Observable
.if(
//a function that returns true or false
() => some_condition,
//Observable to emitif condition is true
methodA().switchMap(() => methodB()),
//Observable to emit if condition is false
methodA()
)
.subscribe(() => {}, error => {}, methodC)
};
Here is the working JSBin for you.
More on Observable.if(): https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/if.md
As #CozyAzure said, Observable.if() is what you want. Make sure to make use of Observable.merge() and Observable.concat().
const methodA = () => Observable.timer(500).mapTo("doing some work A")
const methodB = () => Observable.timer(250).mapTo("doing some work B")
const methodC = () => Observable.of("should be the last...")
const main = (some_condition) =>
Observable.if(
() => some_condition,
methodA().merge(methodB()),
methodA()
)
.concat(methodC())
.subscribe(console.log)
main(true)
Here's the example in jsfiddle
If you're working with promises, you may want to defer the creation of your promise. For example,
const methodA = () => Observable.timer(500).mapTo("doing some work A")
const methodB = () => Observable.timer(250).mapTo("doing some work B")
const methodC = () => Promise.resolve("should be the last...")
Observable.merge(methodA(), methodB())
.concat(Observable.defer(() => methodC())
.subscribe(console.log)

Async transactions in javascript

First of all rollback is something that I do not care about.
I would like to be able to lock a sequence of async functions/promises/tasks (let's call it a "transaction") with a name/id (or array of names), so that they happen in sequence, and so that any other "transaction" with the same name(s) that are run by another part of the system are delayed from starting until the running transaction using the same name(s) has completed. So it basically is queueing the sequences of async tasks, or "transaction"s.
Here is some example code of the situation:
function a()
{
// do stuff
return new Promise(/*...*/);
}
function b()
{
// do stuff
return new Promise(/*...*/);
}
function c()
{
// do stuff
return a.then(() => b());
}
Now at any time the system could call a, b, or c, and when it does I don't want c and b running at the same time, but obvious c depends on b.
I've been looking for a package on npm to help with this but I haven't found anything, I wonder if anyone can suggest something that I might have missed that would help with this?
I think gulp tasks can help you out of the box. This guarantees that c always run after b and so b after a
const gulp = require('gulp');
gulp.task('a', done => {
// do stuff
console.log('a');
done();
});
gulp.task('b', ['a'], done => {
// do stuff
console.log('b');
done();
});
gulp.task('c', ['b'], done => {
// do more stuff
console.log('c');
done();
});
gulp.start('c'); // Logs a, b, c
Try it!
You could write your own little transaction manager.
const transactions = {};
function doTransaction(name, promiseFunc) {
transactions[name] = (transactions[name] || Promise.resolve()).then(promiseFunc);
}
Use async/await and have babel transpile it. Async Babel Docs
function a()
{
// do stuff
return new Promise(/*...*/);
}
async function b()
{
const aData = await a();
// do stuff
return new Promise(/*...*/);
}
async function c()
{
const bData = await b();
// do stuff
return bData;
}
You can go for https://github.com/Reactive-Extensions/RxJS
They have many functions to handle single/multiple/dependent/parallel async calls.
function a()
{
// do stuff
return new Promise(/*...*/);
}
function b()
{
// do stuff
return new Promise(/*...*/);
}
function c()
{
// do stuff
return new Value;
}
a().then(function(data_a) {
// you can make use of return value (which is data_a) here or as an argument for function b or even function c
b().then(function(data_b) {
// you can make use of return value (which is data_b) here or as an argument for function c
c().then(function(data_c) {
// do your coding here
});
});
});
you can check this link for reference : https://spring.io/understanding/javascript-promises
Ok, here's my take.
You use a wrapper for your function b which returns and object with 2 methods: doCall and wait. The wrapper should be called only once.
doCall will call your function and trace its completion for the wait() function.
wait() will wait for the completion and always resolve when doCall() finishes
Now for the code, also on CodePen (see developer console):
function wrapPromiseFn(fn) {
var prev = null;
var doCall = function() {
var retValue;
prev = new Promise(function(resolve, reject) {
retValue = fn();
retValue.then(function(result) {
resolve(true);
});
retValue.catch(function(result) {
resolve(true);
});
});
return retValue;
};
var wait = function() {
return prev ? prev : Promise.resolve(false);
};
return {
doCall: doCall,
wait: wait
};
}
function a() {
return Promise.resolve(42);
}
function b() {
//return Promise.reject(new Date());
return Promise.resolve(new Date().getTime());
}
var wrappedB = wrapPromiseFn(b);
function doStuff() {
return wrappedB.wait().then(function(didWait) {
return a().then(function(_a) {
return wrappedB.doCall().then(function(_b) {
console.log("didWait, a, b: ", didWait, _a, _b);
});
});
});
}
//run it twice to prove it did wait
doStuff().then(doStuff)
It proves the concept, of course it would need some polish to pass arguments from doCall to the wrapped function.

Categories