I have 3 functions that both take their specific time to execute, then when they are all finished I need to trigger a certain function. With the following code, I am able to get the expected results with a single function but with multiple function I am failing to do it, please help me edit this code to wait for my 3 functions then console the data they returned.
var promise = new Promise(function(resolve, reject)
{
setTimeout(function()
{
resolve('hello world');
}, 2000);
});
promise.then(function(data)
{
console.log(data);
});
Javascript has an inbuilt method that waits for all you promises to resolve.
Promise.all([promise1, promise2, promise3]).then(function(values) {
console.log(values);
});
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
So for your case:
const promiseFunction = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('resolved');
}, 2000);
});
};
const promise1 = promiseFunction();
const promise2 = promiseFunction();
const promise3 = promiseFunction();
Promise.all([promise1, promise2, promise3])
.then((result) => {
console.log(result[0]);
console.log(result[1]);
console.log(result[2]);
})
Result is an array of values returned from each promise.
Promise.all() will take an array of promises as a parameter and wait for all promises to complete.
var promise1 = new Promise(function (resolve, reject) {
setTimeout(function () {
resolve('function 1 resolved');
}, Math.random() * 10000);
});
var promise2 = new Promise(function (resolve, reject) {
setTimeout(function () {
resolve('function 2 resolved');
}, Math.random() * 10000);
});
var promise3 = new Promise(function (resolve, reject) {
setTimeout(function () {
resolve('function 3 resolved');
}, Math.random() * 10000);
});
Promise.all([promise1, promise2, promise3])
.then(resArr => {
console.log(resArr)
})
You can catch the error occurred in any of promise by using .catch() attached to promise.all()
Promise.all([promise1, promise2, promise3])
.then(resArr => {
console.log(resArr)
})
.catch(error => console.log(error))
You can refer this code, where the function is called 3 times, and there are 2 ways you can do this and you can also see a different behavior.
// Function which returns a promise and resolves in 2 seconds
const promiseFunction = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('resolved');
}, 2000);
});
};
// Asynchronous function 1
const asyncFunction1 = async() => {
console.log(await promiseFunction());
console.log(await promiseFunction());
console.log(await promiseFunction());
}
// Asynchronous function 2
const asyncFunction2 = async() => {
let a = promiseFunction();
let b = promiseFunction();
let c = promiseFunction();
console.log(await a);
console.log(await b);
console.log(await c);
}
See the difference between
asyncFunction1() and asyncFunction2() calls
using async/await is a ES6 way, you can also do .then() chaining
promiseFunction().then(() => {
//function body here
})
you can chain your promises, like so:
new Promise(function(resolve, reject) {
resolve(1);
}).then(function(result) {
// result is 1
return result * 2;
}).then(function(result) {
// result is 2
return result * 2;
}).then(function(result) {
// result is 4
return result * 2;
});
To keep the results of all functions, you could have the result be an array, and push the new result to it every time. Like so:
new Promise(function(resolve, reject) {
resolve([0]);
}).then(function(result) {
result.push(1);
return result;
}).then(function(result) {
result.push(2);
return result;
}).then(function(result) {
result.push(3);
console.log(result);
return result;
});
This will log [0,1,2,3]
If the promises are independent of each other then use Promise.all:
Promise.all([promise1, promise2, promise3]).then(console.log);
Related
I am trying to write a polyfill for Promise.all, it is working fine when I passed promises without setTimeout, but with setTimeout, I am not getting the correct results since it resolves and returns the promise before the timer expires.
How can this case be handled to work in the below function, in the same way as actual Promise.all works.
Below is my code snippet and link to codesandbox
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => resolve("success 1"), 2000);
});
const promise2 = new Promise((resolve, reject) => {
resolve("success 2");
});
const promise3 = new Promise((resolve, reject) => {
resolve("success 3");
});
function resolveAll(promiseArr) {
let arr = [];
return new Promise((resolve, reject) => {
promiseArr.map((each_promise, index) => {
return each_promise
.then((res) => {
arr[index] = res;
if (index === promiseArr.length - 1) {
resolve(arr);
}
})
.catch((err) => {
reject(err);
});
});
});
}
resolveAll([promise1, promise2, promise3])
.then((res) => {
console.log(res, "result");
})
.catch((err) => console.log(err, "error"));
Actual result : [undefined, "success 2", "success 3"]
Expected result: ["success 1", "success 2", "success 3"]
https://codesandbox.io/s/fast-bush-6osdy?file=/src/index.js
Your problem is that
if (index === promiseArr.length - 1) {
resolve(arr);
}
just checks whether the last promise has resolved, but in your scenario the first promise is the last one that gets resolved because of the setTimeout.
One solution would be to keep a count of how many of the promises have resolved, e.g.
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => resolve("success 1"), 2000);
});
const promise2 = new Promise((resolve, reject) => {
resolve("success 2");
});
const promise3 = new Promise((resolve, reject) => {
resolve("success 3");
});
function resolveAll(promiseArr) {
let arr = [],
errorMsg = [],
resolvedPromiseCount = 0;
return new Promise((resolve, reject) => {
promiseArr.map((each_promise, index) => {
return each_promise.then((res) => {
console.log(res)
arr[index] = res;
resolvedPromiseCount++;
if (resolvedPromiseCount === promiseArr.length) {
resolve(arr);
}
})
.catch((err) => {
resolvedPromiseCount++;
errorMsg.push(err);
});
});
});
}
resolveAll([promise1, promise2, promise3]).then((res) => {
console.log(res, "result");
})
.catch((err) => console.log(err, "error"));
Say, I have three javascript functions
function1 and function2 are executed asynchronously
function2 is to be executed after first two is executed completely
How can this be worked out?
You can do that with Promise.all() (see here)
Example from MDN:
var promise1 = Promise.resolve(3);
var promise2 = 42;
var promise3 = new Promise(function(resolve, reject) {
setTimeout(resolve, 100, 'foo');
});
Promise.all([promise1, promise2, promise3]).then(function(values) {
console.log(values);
});
// expected output: Array [3, 42, "foo"]
Idea of promise chaining or async await keywords should work for you. See below example for promise chaining.
new Promise(function(resolve, reject) {
}).then(function(result) {
}).then(function(result) {
}).then(function(result) {
});
You can chain promises like this:
function f1() {
return new Promise(function(resolve) {
setTimeout(() => resolve('f1'), 1000);
});
}
function f2() {
return new Promise(function(resolve) {
setTimeout(() => resolve('f2'), 1000);
});
}
function f3() {
return new Promise(function(resolve) {
setTimeout(() => resolve('f3'), 1000);
});
}
// Chain promises
f1()
.then((res) => {
console.log(res + ' done!')
return f2()
})
.then((res) => {
console.log(res + ' done!')
return f3()
})
.then((res) => {
console.log(res + ' done!')
})
Or you can group promises:
function f1() {
return new Promise(function(resolve) {
setTimeout(() => resolve('f1'), 1000);
});
}
function f2() {
return new Promise(function(resolve) {
setTimeout(() => resolve('f2'), 1000);
});
}
function f3() {
return new Promise(function(resolve) {
setTimeout(() => resolve('f3'), 1000);
});
}
// Group promises
Promise.all([f1(), f2()])
.then((responses) => {
console.log(responses.join(', ') + ' done!')
return f3()
})
.then((res) => {
console.log(res + ' done!')
})
const promise1 = fn1();
const promise2 = fn2();
Promise.all([promise1, promise2])
.then(values => {
// Your code
});
With async/await you have to declare fn1 and fn2 as async, and then:
const promise1 = await fn1();
const promise2 = await fn2();
// Now the two vars contain resolved promises
async/await is probably more readable, but it will take more time because fn2() is not executed until promise from fn1() is fulfilled. In the first example with Promise.all the two functions are called in parallel and so it will be slightly more performant.
Check this great article from Jake Archibald about async/await if you want to learn more: https://developers.google.com/web/fundamentals/primers/async-functions
Thanks all. I tried all your solutions. Didn't quite work. I created a solution myself after trying for a while. Here it is:
let promise1 = new Promise(function(resolve, reject) {
setTimeout(() => resolve("promise1"), 1000);
});
let promise2 = new Promise(function(resolve, reject) {
setTimeout(() => resolve("promise2"), 4000);
});
Promise.all([promise1, promise2])
.then(result => {
console.log(result);
});
It creates two functions that runs the two functions as resolve. Then it is passed to Promise.all in an array, and the third function can be run in the then block of Promise.all.
I am unable to retrieve data from a promise using then(). Where am I going wrong?
async function A(){
await new Promise((resolve, reject) => setTimeout(()=>{},1000));
return 45;
}
A().then(data => console.log(data))
I'm running this code with nodejs.
I expect the output to print 45. But the program just executes for 1 second and doesn't print anything.
If I remove the timeout statement, I am able to print 45.
Where am I going wrong?
You need to resolve your promise and then return can run.
async function A() {
await new Promise((resolve, reject) => setTimeout(() => resolve(), 1000));
return 45;
}
A().then(data => console.log(data))
You could also return promise from A function and then use async/await.
function A() {
return new Promise((resolve, reject) => {
setTimeout(() => resolve(45), 1000)
})
}
(async() => {
const res = await A();
console.log(res)
})()
Your function A should return a promise.
function A() {
return new Promise((resolve, reject) => setTimeout(() => resolve('hello'), 1000));
}
A().then(data => console.log(data))
Function A should return a promise and use async/await along with IFI (Immediate Function Invocation method)
function A(){
return new Promise((resolve, reject) => setTimeout(()=>{resolve(100)},1000));
}
(async () => {
var data = await A()
console.log(data)
})();
I have a situation where I think the only choice for me is to nest some Promises within each other. I have a Promise that needs to be performed and a method that does something until that Promise is complete. Something like this:
let promise = new Promise((resolve, reject) => {
// Do some stuff
});
doSomethingUntilPromiseisDone(promise);
However, within my Promise, I need to execute another method that returns another Promise:
let promise = new Promise((resolve, reject) => {
fetchValue(url)
.then((value) => {
// Do something here
}).catch((err) => {
console.error(err);
});
});
doSomethingUntilPromiseisDone(promise);
But now, in the fetchValue method's then statement, I have another method I need to execute that, guess what, returns another Promise:
let promise = new Promise((resolve, reject) => {
fetchValue(url)
.then((value) => {
saveToCache(value)
.then((success) => {
console.log('success!!');
resolve('success');
});
}).catch((err) => {
console.error(err);
});
});
doSomethingUntilPromiseisDone(promise);
So in the end, I have a Promise, within a Promise, within a Promise. Is there someway I can structure this better so that it is more straightforward? It seems like nesting them within each other is counter to Promise's intended chaining approach.
Use .then()
let doStuff = (resolve, reject) => {/* resolve() or reject() */};
let promise = new Promise(doStuff);
doSomethingUntilPromiseisDone(
promise
.then(value => fetchValue(url))
.then(value => value.blob())
.then(saveToCache)
)
.then(success => console.log("success!!"))
.catch(err => console.error(err))
you can use generator to flatten your nested promises (Bluebird.couroutine or Generators)
//Bluebird.couroutine
const generator = Promise.coroutine(function*() {
try {
const value = yield fetchValue(url);
const success = yield saveToCache(value);
console.log('success:', success);
} catch(e) {
console.error(err);
}
}));
generator();
Each function will call the next one with the result of the method before.
var promises = [1,2,3].map((guid)=>{
return (param)=> {
console.log("param", param);
var id = guid;
return new Promise(resolve => {
// resolve in a random amount of time
setTimeout(function () {
resolve(id);
}, (Math.random() * 1.5 | 0) * 1000);
});
}
}).reduce(function (acc, curr, index) {
return acc.then(function (res) {
return curr(res[index-1]).then(function (result) {
console.log("result", result);
res.push(result);
return res;
});
});
}, Promise.resolve([]));
promises.then(console.log);
In my code below, I would like to execute a, b and c but then a1 since a1 is added within a. However, it doesn't look like Promise.all is updated with the new a1 added. What's the best way to do this? Is there Promise all update? I try not to do await a1 within a.
var arr = [];
async function a() {
return new Promise(resolve => {
setTimeout(() => {
console.log("Resolve a");
arr.push(a1);
resolve(1);
}, 2000);
});
}
async function b() {
return new Promise(resolve => {
setTimeout(() => {
console.log("Resolve b");
resolve(2);
}, 4000);
});
}
async function c() {
return new Promise(resolve => {
setTimeout(() => {
console.log("Resolve c " + arr.length);
resolve(3);
}, 6000);
});
}
async function a1() {
return new Promise(resolve => {
setTimeout(() => {
console.log("Resolve a1");
resolve(11);
}, 2000);
});
}
arr = [a(), b(), c()];
(async function run() {
await Promise.all(arr);
})();
console.log('Done');
For a start, you push a1 where I think you'd want to push a1() - otherwise you're pushing a function, not a promise
But that won't change anything, because the array passed to Promise.all is (in every library I've seen) copied (using Array#slice) so any changes to the passed in array won't be "visible" to the Promise.all (internal) code
But, you can create a function that recursively calls Promise.all on the array until the length of the results is equal to the (current, new) length of the array
var recursiveAll = a => Promise.all(a).then(r => r.length == a.length ? r : recursiveAll(a));
var arr = [];
async function a() {
return new Promise(resolve => {
setTimeout(() => {
console.log("Resolve a");
arr.push(a1());
resolve(1);
}, 200);
});
}
async function b() {
return new Promise(resolve => {
setTimeout(() => {
console.log("Resolve b");
resolve(2);
}, 400);
});
}
async function c() {
return new Promise(resolve => {
setTimeout(() => {
console.log("Resolve c " + arr.length);
resolve(3);
}, 600);
});
}
async function a1() {
return new Promise(resolve => {
setTimeout(() => {
console.log("Resolve a1");
resolve(11);
}, 200);
});
}
arr = [a(), b(), c()];
(async function run() {
let results = await recursiveAll(arr);
console.log(results);
})();
Interesting question...
You may indeed modify Promise.all() on the run by replacing a promise with another one even if the newly inserted one resolves the latest.
In the below example promise three will replace itself with a new promise which will resolve in an additional 2000ms later and Promise.all() will wait until it to resolves to include it's resolving value to the array provided to the .then() stage.
var fun = _ => new Promise((v,x) => setTimeout(v,2000,5)),
one = new Promise((v,x) => setTimeout(v,1000,1)),
two = new Promise((v,x) => setTimeout(v,2000,2)),
three = new Promise((v,x) => setTimeout(v,3000,fun())),
four = new Promise((v,x) => setTimeout(v,4000,4));
Promise.all([one,two,three,four])
.then(a => console.log(a));
Please wait for 5 seconds to see the result.