3

this question i asked AI about it to rate my knowledge my answer is Resolved: A Rejected: B Resolved: C , but when i ran it on nodejs runtime env and even browser it outputs Resolved: A Resolved: C Rejected: B

function* generatorFunction() {
  yield Promise.resolve("A");
  yield Promise.reject("B");
  yield Promise.resolve("C");
}

const generator = generatorFunction();

for (const promise of generator) {
  promise
    .then((value) => console.log("Resolved:", value))
    .catch((error) => console.log("Rejected:", error));
}

2 Answers2

1

Your code is placing the catch handler on the promise returned from .then(), not the original promise. If you attach them both to the original promise, you get the sequence you expect:

for (const promise of generator) {
  promise.then((value) => console.log("Resolved:", value));
  promise.catch((error) => console.log("Rejected:", error));
}

You'll also get an unhandled rejection error from the first promise chain (the .then() chain. To deal with that, you can put a dummy catch on that one:

for (const promise of generator) {
  promise.then((value) => console.log("Resolved:", value)).catch(_ => _);
  promise.catch((error) => console.log("Rejected:", error));
}

It's a little clearer using await (well to me it is):

(async () => {
for (const promise of generator) {
  try {
    console.log("Resolved:", await promise);
  }
  catch(e) {
    console.log("Rejected:", e);
  }
}})()

edit — Bergi points out that the original problem could also be solved by assigning both the resolved handler and the rejection handler in the original .then() call:

for (const promise of generator) {
  promise.then(
    (value) => console.log("Resolved:", value), // happy
    (error) => console.log("Rejected:", error)  // not happy
  );
}
Pointy
  • 405,095
  • 59
  • 585
  • 614
  • "*To deal with that, you can put a dummy catch on that one*" - no, just use [`.then(…, …)` instead of `.then(…).catch(…)`](https://stackoverflow.com/q/24662289/1048572)! – Bergi Aug 13 '23 at 17:00
  • @Bergi sure, that'd work of course. I still think it's much clearer with `await`. *edit* oh wait, you mean that solves the original problem. Yes, yes it does. I'll update the answer. – Pointy Aug 13 '23 at 17:01
  • That solves both the original problem and is also a better solution to avoid the unhandled rejection when branching `.…then();` – Bergi Aug 13 '23 at 18:19
1

Your .then() and .catch() calls are adding functions to the event loop. Each time your loop gets the generator further, a new Promise is either resolved or rejected, that is, a function is added to the event loop. But, since the .catch is chained to the .then, which is also a promise and adds a function to the event loop because of the catch as well. Therefore, the event loop reached the .then() of B first which added a function to the event loop and this second function is executed after the .then() functions of A and C. You can use the fact that you can pass the resolve handler as the first parameter and the reject handler as the second parameter to the .then() call to your advantage:

function* generatorFunction() {
  yield Promise.resolve("A");
  yield Promise.reject("B");
  yield Promise.resolve("C");
}

const generator = generatorFunction();

for (const promise of generator) {
  promise
    .then((value) => console.log("Resolved:", value), (error) => console.log("Rejected:", error));
}
Lajos Arpad
  • 64,414
  • 37
  • 100
  • 175