Reputation: 21
Summary
This code represents a functionality that executes an array of promises and returns their resolved values in the order they were resolved. It also includes a limiter that restricts the number of promises that can be resolved from the given promise array.
Constraints
If the limiter exceeds the length of the promise array, throw a rejection. If any of the promises throws an error, throw a rejection. If the number of resolved promises reaches the limiter value, return the resolved promises in the order of their resolution and ignore the rest of the promises.
Problem
I have two different versions of the code:
v1 - implements a then-catch chain to execute the functionality. v2 - implements a then with the resolve and reject callbacks as two parameters. In the case of v1, the promises resolve without throwing a rejection even if a promise in this promise list rejects.
However, in the case of v2, the code works as expected, i.e., it throws a rejection when any of the promises rejects.
Code
v1
async function somePromises(promises, promisesToWait) {
// Throws error if promises to wait for is greater than promises in the `promise` array
if (promisesToWait > promises.length) {
return Promise.reject("Count is greater than the number of promises");
}
return await new Promise((resolve, reject) => {
const resolvedPromiseValues = []; // stores the values of resolved values
let hasRejected = false; // tracks the rejection
promises.forEach((promise) => {
promise()
.then((resolvedValue) => {
// Does not execute if rejected. SOMEHOW, NOT WORKING in v1
if (hasRejected) return;
if (resolvedPromiseValues.length < promisesToWait) {
resolvedPromiseValues.push(resolvedValue);
if (resolvedPromiseValues.length === promisesToWait) {
resolve(resolvedPromiseValues);
}
}
})
.catch((error) => {
if (!hasRejected) {
hasRejected = true;
}
reject(error);
});
});
});
}
const rejectablePromises = [
() => Promise.resolve(1),
() => Promise.resolve(2),
() => Promise.reject("I will reject"),
() => Promise.resolve(3),
];
async function main() {
somePromises(rejectablePromises, 3).then(console.log).catch(console.error);
}
main();
// Expected output: I will reject
// Actual output: [1, 2, 3]
v2
async function somePromises(promises, promisesToWait) {
// Throws error if promises to wait for is greater than promises in the `promise` array
if (promisesToWait > promises.length) {
return Promise.reject("Count is greater than the number of promises");
}
return await new Promise((resolve, reject) => {
const resolvedPromiseValues = []; // stores the values of resolved values
let hasRejected = false; // tracks the rejection
promises.forEach((promise) => {
promise().then(
(resolvedValue) => {
// Should not execute if rejected. WORKS AS EXPECTED in v2
if (hasRejected) return;
if (resolvedPromiseValues.length < promisesToWait) {
resolvedPromiseValues.push(resolvedValue);
if (resolvedPromiseValues.length === promisesToWait)
resolve(resolvedPromiseValues);
}
},
(error) => {
if (!hasRejected) {
hasRejected = true;
}
reject(error);
}
);
});
});
}
const rejectablePromises = [
() => Promise.resolve(1),
() => Promise.resolve(2),
() => Promise.reject("I will reject"),
() => Promise.resolve(3),
];
async function main() {
somePromises(rejectablePromises, 3).then(console.log).catch(console.error);
}
main();
// Expected output: I will reject
// Actual output: I will reject
Is there a difference between these two of implementing promises? I read the docs but couldn't find any clarity between the two. Asked ChatGPT, it says the just a matter of readability.
What am I missing?
Upvotes: 0
Views: 82
Reputation: 137094
There are 2 main differences:
.then(a).catch(b)
will handle the errors thrown during the execution of a
, while .then(a, b)
wouldn't:Promise.resolve(1)
.then(() => { throw "bad" })
.catch((err) => console.log("caught in .catch()"));
Promise.resolve(1)
.then(() => { throw "bad" }, (err) => console.log("caught in .then()"));
.then(a).catch(b)
will span over two microtasks: the one from then()
and the one from .catch()
:// The Promises's microtasks will be interleaved with these ones
queueMicrotask(() => {
console.log("microtask 1");
queueMicrotask(() => {
console.log("microtask 2");
queueMicrotask(() => {
console.log("microtask 3");
});
});
});
Promise.reject("bad")
.then(() => { })
.catch((err) => console.log("caught in .catch()"));
Promise.reject("bad")
.then(() => { }, (err) => console.log("caught in .then()"));
While the first difference is probably something you want to keep in mind, your issue arises from the second one. Since all your Promises are already settled, when using .then().catch()
you will pick only the resolved ones and move the rejected ones at the end of the list, and actually ignoring it in your example.
Upvotes: 2