promise rejection 在 then-catch chaining 和 then(resolveCallback, rejectCallback) 之间的工作方式不同

Promise rejection works differently between then-catch chaining and then(resolveCallback, rejectCallback)

提问人:Nawaaz Kortiwala 提问时间:11/13/2023 最后编辑:KaiidoNawaaz Kortiwala 更新时间:11/13/2023 访问量:69

问:

总结

此代码表示一个功能,该功能执行 promise 数组,并按解析顺序返回其解析的值。它还包括一个限制器,用于限制可以从给定的 promise 数组中解析的 promise 数量。

约束

如果限制器超过promise数组的长度,则抛出拒绝。 如果任何 promise 抛出错误,则抛出拒绝。 如果已解析的 promise 数量达到限制器值,则按解析的顺序返回已解析的 promise,并忽略其余的 promise。

问题

我有两个不同版本的代码:

v1 - 实现一个 then-catch 链来执行该功能。 v2 - 实现 then,并将 resolve 和 reject 回调作为两个参数。 在 v1 的情况下,即使此承诺列表中的 promise 被拒绝,promise 也会解析而不会引发拒绝。

但是,在 v2 的情况下,代码按预期工作,即当任何 promise 拒绝时,它会抛出拒绝。

法典

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]


2 版

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

这两者在实现承诺方面有区别吗?我阅读了文档,但找不到两者之间的任何清晰度。当问ChatGPT时,它说的只是可读性的问题。

我错过了什么?

JavaScript 承诺

评论

1赞 Ry- 11/13/2023
你可能有一场比赛——有一个函数规范要求你拒绝任何拒绝忽略任何拒绝,条件是这些事情可能同时发生,就像他们的测试用例一样。
0赞 SoZettaSho 11/13/2023
这只是日程安排。你实际上并没有拒绝“当任何一个承诺被拒绝时”,也没有任何拒绝的承诺实际上阻止了回调推送到。它所做的只是等待 3 个承诺,只要 3 个承诺解决,即使后来有人拒绝,您也可以继续。承诺本质上是异步的,关键不是要假设异步事情发生的顺序或需要多长时间somePromisethenresolvedPromiseValues
0赞 SoZettaSho 11/13/2023
要实现您想要的(从其他 promise 创建一个 promise,如果任何其他 promise 拒绝,则拒绝,请使用promise.all

答:

2赞 Kaiido 11/13/2023 #1

有 2 个主要区别:

  • .then(a).catch(b)将处理 执行期间抛出的错误,而不会:a.then(a, b)

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)将跨越两个微任务:一个来自,一个来自:then().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()"));

虽然第一个区别可能是你要记住的,但你的问题来自第二个区别。由于你所有的 Promise 都已经解决,所以在使用时,你只会选择已解决的 Promise,并将被拒绝的 Promise 移到列表的末尾,并在你的示例中忽略它。.then().catch()