Combining async operations into one synchronous operation - javascript

I have a requirement where I need to call multiple APIs asynchronously and combine the result of all the APIs and return it. The issue here is, I need to use this complete method as synchronous wherever I will be using it.
Note: I can't use any of the libraries/frameworks.
function op1() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve({
firstName: "Nikhil"
});
}, 1000);
});
}
function op2() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve({
lastName: "Goyal"
});
}, 500);
});
}
function getName() {
// Some implementation here
}
const name = getName();
console.log(name.firstName);
console.log(name.lastName);

Try using async and await.
function op1() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve({
firstName: "Nikhil"
});
}, 1000);
});
}
function op2() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve({
lastName: "Goyal"
});
}, 500);
});
}
async function getName() {
const a = await op1();
const b = await op2();
return {firstName: a.firstName, lastName: b.lastName}
}
getName().then(name=> {
console.log(name.firstName);
console.log(name.lastName);
}
);

Related

Promise resolution returns undefined value but i have returned with resolve [duplicate]

This question already has answers here:
When should I use a return statement in ES6 arrow functions
(6 answers)
Closed 2 years ago.
console.log("Before");
getUser(1)
.then((user) => getRepositories(user.gitHubUsername))
.then((repos) => {
getCommits(repos[0]);
})
.then((commits) => {
console.log("commits: ", commits);
})
.catch((err) => console.log("Error: ", err.message));
console.log("After");
function getUser(id) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("Reading a user from a database...");
resolve({
id: id,
gitHubUsername: "mosh"
});
}, 2000);
});
}
function getRepositories(username) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("Calling GitHub API...");
resolve(["repo1", "repo2", "repo3"]);
}, 2000);
});
}
function getCommits(repo) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("Calling GitHub API...");
resolve("commit");
}, 2000);
});
}
now here evey function which is chained is contains a promise which is resolving something i.e username, array etc. but when i run this code on the console it displays commnits : undefined
you can see it in this attached image
You missed the return:
console.log("Before");
getUser(1)
.then((user) => getRepositories(user.gitHubUsername))
.then((repos) => {
return getCommits(repos[0]);
})
.then((commits) => {
console.log("commits: ", commits);
})
.catch((err) => console.log("Error: ", err.message));
console.log("After");
function getUser(id) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("Reading a user from a database...");
resolve({
id: id,
gitHubUsername: "mosh"
});
}, 2000);
});
}
function getRepositories(username) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("Calling GitHub API...");
resolve(["repo1", "repo2", "repo3"]);
}, 2000);
});
}
function getCommits(repo) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("Calling GitHub API...");
resolve("commit");
}, 2000);
});
}

What is wrong with this async-await code (javascript)?

I am very new to asynchronous JavaScript. I am trying to add a new member to a zoo and then display the updated list of zoo animals in the following code. the new animal is being admitted successfully but the method to display updated list of zoo animals is not working. Can anyone plz point out what is going on here?
let zoo = [
{ animal: "elephant", age: 15 },
{ animal: "rhino", age: 10 },
{ animal: "tiger", age: 6 },
];
const admit = (animal) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
zoo.push(animal);
resolve: console.log(
`new ${animal.animal} added. now ${zoo.length} animals.`
);
//reject: console.log("something went wrong");
}, 2000);
});
};
const displayZoo = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve: console.table(zoo);
reject: console.log("something went wrong while displaying animals");
}, 3000);
});
};
const doSomething = async () => {
try {
let admission = await admit({ animal: "lion", age: 13 });
await displayZoo();
console.log("everything went fine");
} catch (err) {
console.log(err);
}
};
doSomething();
resolve and reject in the Promise constructor are functions. With async/await syntax, you call resolve with the value to return to the function that is await-ing or call reject with an object to throw.
Your code is in charge of determining when an error has occurred to decide whether to call resolve or reject.
let zoo = [
{ animal: "elephant", age: 15 },
{ animal: "rhino", age: 10 },
{ animal: "tiger", age: 6 },
];
const admit = (animal) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
zoo.push(animal);
resolve(`new ${animal.animal} added. now ${zoo.length} animals.`);
// `await admit()` will return this string ^
}, 2000);
});
};
const displayZoo = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (Math.random() > 0.5) { // To simulate some failure condition
console.table(zoo);
resolve();
// `await displayZoo()` will return undefined (void function)
} else {
reject('There was an error');
// `await displayZoo()` will throw this string ^
}
}, 3000);
});
};
const doSomething = async () => {
try {
let admission = await admit({ animal: "lion", age: 13 });
console.log(admission);
await displayZoo();
console.log("everything went fine");
} catch (err) {
console.log(err);
}
};
doSomething();

How do I consume this second promise?

Here's the code
console.log("Before");
const p = getUser(1);
p.then(user => {
console.log(user);
getRepositories(user.github);
}).then(repos => {
console.log(repos);
});
console.log("after");
function getUser(id) {
return new Promise(function(resolve, reject) {
setTimeout(() => {
console.log("Calling a database " + id);
resolve({ id: id, github: "Zain" });
}, 2000);
});
}
function getRepositories(username) {
return new Promise(function(resolve, reject) {
setTimeout(() => {
console.log(`Calling Api for ${username}`);
resolve(["repo1", "repo2", "repo3"]);
}, 2000);
});
}
I'm having trouble with consuming the promise returned by getRepositories() function. Above is my implementation but it doesn't work and returns undefined (instead of the array [repo1, repo2, repo3]).
Here's the output:
I want the array to return after logging "Calling Api for Zain" but the undefined is shown before it, but I don't know why, so I need help regarding this.
You need a return statement in your first .then:
p.then(user => {
console.log(user);
return getRepositories(user.github);
}).then(repos => {
console.log(repos);
});
There’s a special syntax to work with promises in a more comfortable fashion, called “async/await”. It’s surprisingly easy to understand and use.
async function init() {
console.log("Before");
const user = await getUser(1);
console.log(user);
const repos = await getRepositories(user.github);
console.log(repos);
console.log("after");
}
init();
async function getUser(id) {
return new Promise(function(resolve, reject) {
setTimeout(() => {
console.log("Calling a database " + id);
resolve({ id: id, github: "Zain" });
}, 2000);
});
}
async function getRepositories(username) {
return new Promise(function(resolve, reject) {
setTimeout(() => {
console.log(`Calling Api for ${username}`);
resolve(["repo1", "repo2", "repo3"]);
}, 2000);
});
}
For more information: https://javascript.info/async-await

Passing an object an array of it's own promises functions to be executed in series?

I would like to achieve the following: I have a class generating an object with a series of methods.
Each of these is likely to be a promise.
From the outside of it should be possible to pick these methods and compose them into an array and ask the same object to execute them in series.
The code should be something like this (of course this does not work, this is why I'm asking):
class Car{
constructor(){}
fuctionA(input){
// do stuffs
}
fuctionB(input){
// do stuffs
}
fuctionC(input){
// do stuffs
}
fuctionD(input){
// do stuffs
}
executeArrayOfFuctions(array){
// execute each function in the array when the previous is resolved
}
}
const car1 = new Car();
const car2 = new Car();
const arrayOfFunctions = [functionA(input), functionC(input), functionA(input)];
car1.executeArrayOfFuctions(arrayOfFunctions);
car2.executeArrayOfFuctions(arrayOfFunctions);
EDIT: The reason because I pass an arbitrary order of functions from outside the object is because I want to be able to have different combinations of those functions every time.
Like for example a choreography, where you can have many dancers able to perform a number of movements, but not always the same, and not the same for everyone.
Sorry, this was not specified well enough.
EDIT: for #Akshay Bande, I do like how you pass a string reference to the internal methods, but still if I try to really go ahead and defines my methods as promises, with a 1-second timeout to be resolved, they are executed all at once.
I did not really get the Promise.resolve() part.
class Car {
constructor() {}
functionA(input) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("A", input);
resolve();
}, 1000);
});
}
functionB(input) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("B", input);
resolve();
}, 1000);
});
}
functionC(input) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("C", input);
resolve();
}, 1000);
});
}
functionD(input) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("D", input);
resolve();
}, 1000);
});
}
executeArrayOfFuctions(array) {
let p = Promise.resolve();
array.forEach(val => {
p = p.then(() => {
this[val.functionName](val.arg);
return Promise.resolve();
});
});
}
}
const car1 = new Car();
const car2 = new Car();
const arrayOfFunctions = [
{ functionName: "functionA", arg: "1" },
{ functionName: "functionC", arg: "2" },
{ functionName: "functionA", arg: "3" }
];
car1.executeArrayOfFuctions(arrayOfFunctions);
//car2.executeArrayOfFuctions(arrayOfFunctions);
3EDIT:
Thanks #AkshayBande for your help, I think this way can work:
class Car {
constructor() {}
functionA(input) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("A", input);
resolve();
}, 1000);
});
}
functionB(input) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("B", input);
resolve();
}, 1000);
});
}
functionC(input) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("C", input);
resolve();
}, 1000);
});
}
functionD(input) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("D", input);
resolve();
}, 1000);
});
}
async executeArrayOfFuctions(array) {
for (let index = 0; index < array.length; index++) {
await this[array[index].functionName](array[index].arg);
}
}
}
const car1 = new Car();
const car2 = new Car();
const arrayOfFunctions = [
{ functionName: "functionA", arg: "1" },
{ functionName: "functionC", arg: "2" },
{ functionName: "functionA", arg: "3" }
];
car1.executeArrayOfFuctions(arrayOfFunctions);
//car2.executeArrayOfFuctions(arrayOfFunctions);
Or like this:
class Car {
constructor() {}
functionsStack = [];
addFunctionA(input) {
this.functionsStack.push({ fn: "functionA", args: input });
return this;
}
addFunctionB(input) {
this.functionsStack.push({ fn: "functionB", args: input });
return this;
}
addFunctionC(input) {
this.functionsStack.push({ fn: "functionC", args: input });
return this;
}
addFunctionD(input) {
this.functionsStack.push({ fn: "functionD", args: input });
return this;
}
functionA(input) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("A", input);
resolve();
}, 1000);
});
}
functionB(input) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("B", input);
resolve();
}, 1000);
});
}
functionC(input) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("C", input);
resolve();
}, 1000);
});
}
functionD(input) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("D", input);
resolve();
}, 1000);
});
}
start() {
return new Promise((resolve, reject) => {
this.executeArrayOfFuctions(this.functionsStack).then(() => {
this.functionsStack = [];
resolve();
});
});
}
async executeArrayOfFuctions(array) {
for (let index = 0; index < array.length; index++) {
await this[array[index].fn](array[index].args);
}
}
}
const car1 = new Car();
const car2 = new Car();
car1
.addFunctionA("1")
.addFunctionB("2")
.addFunctionC("3")
.addFunctionA("5")
.addFunctionD("6")
.addFunctionB("7")
.start()
.then(() => {
console.log(car1.functionsStack);
});
// const arrayOfFunctions = [
// { functionName: "functionA", arg: "1" },
// { functionName: "functionC", arg: "2" },
// { functionName: "functionA", arg: "3" }
// ];
// car1.executeArrayOfFuctions(arrayOfFunctions);
//car2.executeArrayOfFuctions(arrayOfFunctions);
No, don't make it that complicated. With async/await, you don't need to pass functions around. Also the Car object should not be responsible for being able to run async functions sequentially - that's the job of a simple helper function if you really needed it. But just write
class Car {
constructor() {}
async functionA(input) {
// do stuffs
}
async functionB(input) {
// do stuffs
}
async functionC(input) {
// do stuffs
}
async functionD(input) {
// do stuffs
}
}
async function go(car) {
await car.functionA(input);
await car.functionC(input);
await car.functionA(input);
}
go(new Car()); // car 1
go(new Car()); // car 2
Promises are what you need.
class Car{
constructor(){}
functionA(input){
// do stuffs
console.log(input);
}
functionB(input){
// do stuffs
console.log(input);
}
functionC(input){
// do stuffs
console.log(input);
}
functionD(input){
// do stuffs
console.log(input);
}
executeArrayOfFuctions(array){
// execute each function in the array when the previous is resolved
let p = Promise.resolve();
array.forEach((val)=>{
p = p.then(()=>{
this[val.functionName](val.arg);
return Promise.resolve();
})
})
}
}
const car1 = new Car();
const car2 = new Car();
const arrayOfFunctions = [ {functionName: 'functionA', arg:'1'},{functionName: 'functionC', arg:'2'}, {functionName: 'functionA', arg:'3'} ];
car1.executeArrayOfFuctions(arrayOfFunctions);
//car2.executeArrayOfFuctions(arrayOfFunctions);
According to edit added to the question, If you want to execute functions after one-second delay then you can use this code.
class Car {
constructor() {}
delay(time){
return new Promise(function(resolve,reject){
setTimeout(function(){
resolve();
},time)
})
}
functionA(input) {
this.delay(1000).then(()=>{
console.log('A');
})
}
functionB(input) {
this.delay(1000).then(()=>{
console.log('B');
})
}
functionC(input) {
this.delay(1000).then(()=>{
console.log('C');
})
}
functionD(input) {
this.delay(1000).then(()=>{
console.log('D');
})
}
executeArrayOfFuctions(array) {
let p = Promise.resolve();
array.forEach(val => {
p = p.then(() => {
this[val.functionName](val.arg);
return Promise.resolve();
});
});
}
}
const car1 = new Car();
const car2 = new Car();
const arrayOfFunctions = [
{ functionName: "functionA", arg: "1" },
{ functionName: "functionC", arg: "2" },
{ functionName: "functionA", arg: "3" }
];
car1.executeArrayOfFuctions(arrayOfFunctions);
//car2.executeArrayOfFuctions(arrayOfFunctions);

Async function inside Promises

Here is my situation:
fetchData(foo).then(result => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(result + bar);
}, 0)
});
}).then(result => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve( result + woo);
}, 0)
});
}).then(result => {
setTimeout(() => {
doSomething(result);
}, 0)
});
Where each setTimeout is a different async operation using the callback pattern.
It is really painfull to wrap each function inside a promise, I feel like the code should look more like this:
fetchData(foo).then(result => {
setTimeout(() => {
return result + bar;
}, 0)
}).then(result => {
setTimeout(() => {
return result + woo;
}, 0)
}).then(result => {
setTimeout(() => {
doSomething(result);
}, 0)
});
Obviously this doesn't work.
Am I using Promises right? Do I really have to wrap all existing async function in promises?
EDIT:
Actually I realize my example was not totally reprensentative of my situation, I did not make it clear that the setTimeout in my example is meant to reprensent en async operation. This situation is more representative of my situation:
fetchData(foo).then(result => {
return new Promise((resolve, reject) => {
asyncOperation(result, operationResult => {
resolve(operationResult);
}, 0)
});
}).then(result => {
return new Promise((resolve, reject) => {
otherAsyncOperation(result, otherAsyncResult => {
resolve( otherAsyncResult);
}, 0)
});
}).then(result => {
doSomething(result);
});
Am I using Promises right? Do I really have to wrap all existing async function in promises?
Yes. Yes.
I feel like the code should look more like this
No, it shouldn't. It rather should look like this:
function promiseOperation(result) {
return new Promise((resolve, reject) => {
asyncOperation(result, resolve, 0)
});
}
function otherPromiseOperation(result) {
return new Promise((resolve, reject) => {
otherAsyncOperation(result, resolve, 0)
});
}
fetchData(foo).then(promiseOperation).then(otherPromiseOperation).then(doSomething);
It is really painfull to wrap each function inside a promise
Well, don't repeatedly write it out every time. You can abstract this wrapping into a function!
function promisify(fn) {
return value => new Promise(resolve => {
fn(value, resolve, 0)
});
}
const promiseOperation = promisify(asyncOperation);
const otherPromiseOperation = promisify(otherAsyncOperation);
fetchData(foo).then(promiseOperation).then(otherPromiseOperation).then(doSomething);
Notice that most promise libraries come with a such a promisification function included, so your whole code reduces to these three lines.
You are using promise right. Just a small note on the first snippet of code: you are not returning a promise from the last then() callback:
...
}).then(result => {
setTimeout(() => {
doSomething(result);
}, 0)
});
This is correct if you need simply to do an async operation without returning to the caller of fetchData the value of the last async operation. If you need to return this value, you need to convert to promise this operation too:
fetchData(foo).then(result => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(result + bar);
}, 0)
});
}).then(result => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(result + woo);
}, 0)
});
}).then(result => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(doSomething(result));
}, 0)
});
});
Here I suppose doSomething is a sync function returning a value.
Said so, if you want to reduce the noise of create the promise to wrap setTimeout every time, you can create a utility function setTimeoutWithPromise:
function setTimeoutWithPromise(operation, millisec) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(operation());
}, millisec)
});
}
And clean your code:
fetchData(foo)
.then(result => setTimeoutWithPromise(() => result + bar, 0))
.then(result => setTimeoutWithPromise(() => result + woo, 0))
.then(result => setTimeoutWithPromise(() => doSomething(result), 0));

Categories