I'm working with promises in JavaScript. I need to create three promises that each fulfill to a number. These conditions must be met:
I've made a start but I don't know how to return early if the promises take too long to resolve:
function getPromise(): Promise<number> {
return new Promise(resolve => {
setTimeout(()=>{
resolve(Math.round(Math.random() * 10))
}, Math.random() * 100);
})
};
const TIMEOUT_MS = 50;
async function foo(){
const promises = [getPromise(), getPromise(), getPromise()];
const timeBefore = new Date().getTime()
const results: number[] = await Promise.all(promises);
const timeAfter = new Date().getTime();
const duration = timeAfter - timeBefore;
// if the duration is within 50ms then return the sum of all 3
if(duration <= TIMEOUT_MS) {
const sum: number = results.reduce((acc, current ) => acc + current, 0);
return sum
}
// todo
}
You can do the following:
Create a fourth promise that expires after 50ms and resolves to the value 0, and then wait for three of those four promises to resolve: sum up the values they resolve to for getting the final result. If the 50ms timeout is one of those first three to resolve, then you'll have effectively summed up two of the values of the three given promises (plus 0). If the 50ms-promise is not one of those first three to resolve, then you have all three values of the three given promises. In both cases you get what is asked for:
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
const getPromise = () => delay(Math.random() * 100).then(() => Math.round(Math.random() * 10));
const TIMEOUT_MS = 50;
async function foo() {
const timeout = delay(TIMEOUT_MS).then(() => 0);
// Create the three promises, and add the timeout promise to the set.
// Map each of them to a new promise that also has the index of the promise in its fulfillment value
const promises = [getPromise(), getPromise(), getPromise(), timeout].map((p, i) => Promise.all([p, i]));
// Just for debugging: output when a promise resolves:
for (const p of promises) p.then(console.log, console.error);
let sum = 0;
// Wait for the first three promises to resolve
for (let j = 0; j < 3; j++) {
const [value, i] = await Promise.race(promises.filter(Boolean));
promises[i] = null; // Exclude this promise from the next race
sum += value;
}
return sum;
}
foo().then(sum => console.log("Sum:", sum));
Note that the above snippet also outputs for each promise -- as soon as it gets fulfilled -- an array with two elements:
This allows to verify that the sum is output after three out of four promises have resolved.