Promise.all is not waiting for all promises to get resolved.In Below code I am trying to replicate a scenarios where depending on some service (two services) response I would be setting the array and then when all service call is done, process.all will give the captrued value. However this does not work.
let errorPromises = [];
setTimeout(() => {
errorPromises.push(new Promise((resolve, reject) => resolve(1000)));
}, 2000);
setTimeout(() => {
errorPromises.push(new Promise((resolve, reject) => resolve(3000)));
}, 1000);
let promise = Promise.all(errorPromises);
promise.then(data => {
console.log("All done", data);
});
it should print "All done [1000,3000]" but it prints "All done []"
Please help.
This happens because you are creating promises after the timeout. You need to wrap the timeout in Promise instead
let errorPromises = [];
errorPromises.push(new Promise((resolve, reject) => {
setTimeout(() => resolve(1000), 2000);
}));
// or a one-liner
// errorPromises.push(new Promise(resolve => setTimeout(() => resolve(1000), 2000)));
/// repeat with all others...
let promise = Promise.all(errorPromises);
promise.then(data => {
console.log("All done", data);
});
This happens because you create the promise, before your error promises are in the array. It will take 1 and 2 seconds for the promises to be pushed in the array with timeout, so you get what you want if you wait that the array contains something, for example if you set timeout for the promise too, which should happen AFTER the promises are pushed in to the array.
let errorPromises = [];
setTimeout(() => {
errorPromises.push(new Promise((resolve, reject) => resolve(1000)));
}, 2000);
setTimeout(() => {
errorPromises.push(new Promise((resolve, reject) => resolve(3000)));
}, 1000);
setTimeout(() => {
let promise = Promise.all(errorPromises);
promise.then(data => {
console.log("All done", data);
});
}, 3000);
So basically you trigger the console log instantly, and then your array is still empty because of the timeout.
let errorPromises = [];
errorPromises.push(new Promise((resolve, reject) => resolve(1000)));
errorPromises.push(new Promise((resolve, reject) => resolve(3000)));
let promise = Promise.all(errorPromises);
promise.then(data => {
console.log("All done", data);
});
Related
I am doing tasks with chatGPT and I've got this task
Create a promise that resolves to a string "Hello World" after 2 seconds.
Its answer is:
const greeting = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Hello World");
}, 2000);
});
However, its not working for me. What works for me is:
const myPromise = new Promise((resolve, reject) => {
setTimeout(() =>{
resolve();
}, 2000)
})
myPromise.then(() => console.log('Hello World'))
Why I can't get answer in resolve?
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"));
I am facing an issue while using promise to control async tasks in JavaScript. In the following code, I wanted to output 'first' before 'second'. I used promise then block, but it didn't work as I wanted.
I used setTimeout to create different time delay, so that I can control async tasks order no matter what. Can anyone please help me understand why the code is not giving the output I wanted?
Here is the code:
let first = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(console.log('first'));
}, 30);
});
let second = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(console.log('second'));
}, 3);
});
first.then(second);
I don't believe that your code sample reflects your real situation, so I think it's not useful to solve the issue in your code sample.
Here is what I think you have:
// a task that returns a promise and takes some amount of time
const task = (name) => new Promise(resolve => setTimeout(() => resolve(name), Math.random() * 1000));
// a function using the task result
const taskDone = (name) => console.log(name + ' done');
// two instances of that task, finishing in unpredictable order
var action1 = task('task 1').then(taskDone);
var action2 = task('task 2').then(taskDone);
Run the snippet a few times to see that the result order changes. All you want a way to ensure that 'task 1 done' is always printed before 'task 2 done', even if task 2 finishes earlier.
The way to do this is to use Promise.all().
const task = (name) => new Promise(resolve => setTimeout(() => resolve(name), Math.random() * 1000));
const taskDone = (name) => console.log(name + ' done');
// set up tasks
var allTasks = [task('task 1'), task('task 2')];
// wait for results and evaluate
Promise.all(allTasks).then(allResults => allResults.forEach(taskDone));
allResults will be in the same order as allTasks, so 'task 1 done' will now always be printed before 'task 2 done'.
If you only have two tasks, you can be more explicit:
Promise.all([
task('task 1'),
task('task 2')
]).then(allResults => {
taskDone(allResults[0]);
taskDone(allResults[1]);
});
Wrap it to a function and create a closure and it will be called when you call it right the way.
let first = () => new Promise((resolve, reject) => {
setTimeout(() => {
resolve(console.log('first'));
}, 30);
});
let second = () => new Promise((resolve, reject) => {
setTimeout(() => {
resolve(console.log('second'));
}, 3);
});
first().then(second);
The first problem is that your promise constructor executor functions call console.log() before the promises are even fulfilled. Instead, you should wait to console.log() the values that promises are fulfilled with:
let first = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('first');
}, 30);
});
let second = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('second');
}, 3);
});
first.then((value1) => {
console.log(value1);
});
second.then((value2) => {
console.log(value2);
});
Now for the matter of sequencing the output, you can achieve this by awaiting the fulfilled value of second only after awaiting the fulfilled value of first, rather than awaiting both of them at the same time:
let first = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('first');
}, 30);
});
let second = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('second');
}, 3);
});
first.then((value1) => {
console.log(value1);
return second;
}).then((value2) => {
console.log(value2);
});
If you start two promises parallelly which are resolved by setTimeout then there is no way you can control your logs order.
You need to establish some order dependency between the two to resolve them in order.
One way could be as follows:-
let first = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(console.log('first'));
}, 30);
});
first.then(() => {
let second = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(console.log('second'));
}, 3);
});
return second;
})
I do have 2 function. I am chaining with then() method for promise. But I am trying to initiate the second function after the first promise happend. But now the second function call as first. how to fix this?
or any issue with my code?
here is my try:
var getData = function(){
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(42); //consoles as second
}, 5000);
})
}
var getDataMoreData = function(){
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(43); //consoles as first
}, 3000);
})
}
getData().then((data)=> console.log('Data', data)).then(getDataMoreData().then((data)=> console.log('data--', data )));
Live Demo
.then accepts a function as a parameter. When you do
.then(getDataMoreData()
.then((data) => console.log('data--', data))
);
, it immediately calls getDataMoreData() (with the expectation that it will return a function that it can put into the promise chain). But getDataMoreData does not return a function - it returns a promise.
Any function calls immediately within a then get executed immediately, as it attempts to build the .then promise chain. Simply list the function variable inside the then instead of calling it:
var getData = function() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(42);
}, 500);
})
}
var getDataMoreData = function() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(43);
}, 300);
})
}
getData()
.then((data) => console.log('Data', data))
.then(getDataMoreData)
.then((data) => console.log('data--', data));
I have a promise implementation like the one on MDN:
var p1 = new Promise((resolve, reject) => {
setTimeout(resolve, 1000, "one");
});
var p2 = new Promise((resolve, reject) => {
setTimeout(resolve, 2000, "two");
});
var p3 = new Promise((resolve, reject) => {
setTimeout(resolve, 3000, "three");
});
var p4 = new Promise((resolve, reject) => {
setTimeout(resolve, 4000, "four");
});
var p5 = new Promise((resolve, reject) => {
reject("reject");
});
Promise.all([p1, p2, p3, p4, p5]).then(value => {
console.log(value);
}, function(reason) {
console.log(reason)
});
This does fast error-catching:
Promise.all is rejected if one of the elements is rejected and Promise.all fails fast: If you have four promises which resolve after a timeout, and one calls reject immediately, then Promise.all rejects immediately.
However, the functions inside a promise don't stop running. What I want, is that if one function does a reject, the other functions stop running (preventing useless messages to a user).
Example of a promise that keeps running after the reject:
var p1 = new Promise((resolve, reject) => {
setTimeout(resolve, 1000, "one");
});
var p2 = new Promise((resolve, reject) => {
setTimeout(resolve, 2000, "two");
});
var p3 = new Promise((resolve, reject) => {
setTimeout(resolve, 3000, "three");
});
var p4 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('Don\'t show this after a reject!');
resolve();
}, 4000);
});
var p5 = new Promise((resolve, reject) => {
reject("reject");
});
Promise.all([p1, p2, p3, p4, p5]).then(value => {
console.log(value);
}, function(reason) {
console.log(reason)
});
There's nothing general in promises that will do that, since stopping the other actions is action-specific, not generic. For instance, in your example, you have to keep the timer handle and then use clearTimeout; with an ajax request, you might need to do an abort call; with something else, it would be something else.
So you'll need to handle this in your real code in a way that's specific to your real code, using .catch on the promise returned by Promise.all (or the second arg to then as you have).
In the specific code in your question, it would look something like this (I've added output to the timers we don't cancel as well), but again it will vary depending on what you're cancelling:
var timersToReject = [];
var p1 = new Promise((resolve, reject) => {
setTimeout(v => {
console.log("resolving " + v);
resolve(v);
}, 1000, "one");
});
var p2 = new Promise((resolve, reject) => {
setTimeout(v => {
console.log("resolving " + v);
resolve(v);
}, 2000, "two");
});
var p3 = new Promise((resolve, reject) => {
setTimeout(v => {
console.log("resolving " + v);
resolve(v);
}, 3000, "three");
});
var p4 = new Promise((resolve, reject) => {
timersToReject.push(setTimeout(() => {
console.log('Don\'t show this after a reject!');
resolve();
}, 4000));
});
var p5 = new Promise((resolve, reject) => {
reject("reject");
});
Promise.all([p1, p2, p3, p4, p5]).then(value => {
console.log(value);
}, function(reason) {
console.log(reason)
timersToReject.forEach(t => clearTimeout(t));
});