然后承诺并且catch子句不起作用 [英] Promise then and catch clauses not working

查看:75
本文介绍了然后承诺并且catch子句不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有很多函数可能会或可能不会返回Promise,并且可能会或可能不会失败,例如以下示例:

I have a multitude of functions that may or may not return a Promise and that may or may not fail, like in the examples below:

let goodFun = (fruit) => `I like ${fruit}`;

let badFun = (fruit) => {
    throw `${fruit} is spoiled!`;
};

let badPromise = (fruit) => new Promise( (fulfil, reject) => {
    reject(`Promise failed with ${fruit}`);
});

let goodPromise = (fruit) => new Promise((fulfil, reject) => {
    fulfil(`Promise succeeded with ${fruit}`);
});

由于每个函数可能会也可能不会返回诺言,这可能会失败,所以我修改了<来自executeSafe -might-not-be-bewrapped-in-a-promi>另一个StackOverflow帖子,该帖子将一个函数及其参数作为参数,然后 Promisify 该函数及其结果:

Because each function may or may not return a promise, which may or may not fail, I modified executeSafe from another StackOverflow post, that takes a function and its arguments as parameters, and then Promisifies the function and its result:

let executeSafe =
    (fun, ...args) => Promise.resolve().then(() => {
        return fun(...args);
    });

我的全部目标是拥有 asyncFun 函数,该函数等待已承诺的一批函数的执行,然后返回执行它们的结果:

My objective with all of this, is to have an asyncFun function that waits for the execution of a batch of functions that were Promisified and then returns whatever came from executing them:

let asyncFun = 
(fruit) => 
    Promise.all([badFun, goodFun, badPromise, goodPromise].map(
        fun => executeSafe(fun, fruit)
    )
);



问题



asyncFun 旨在运行前面描述的众多功能,其中一些我实际上希望看到会失败。为此,我的 asyncFun 函数具有 catch 子句。此子句仅适用于 badFun ,不适用于 badPromise then 子句永远无效。

Problem

asyncFun is designed to run the multitude of functions previously described and some of them I actually expect to see fail. To accommodate for this my asyncFun function has a catch clause. This clause only works with badFun and doesn't work with badPromise. The then clause never works.

let executor = () => {
    let fruitsArr = ["banana", "orange", "apple"];
    let results = [];

    for (let fruit of fruitsArr)
        results.push(
            asyncFun(fruit)
            .then(res => {
                console.log(res);
            })
            .catch(error => {
                console.log(`Error: ${error}`);
            })
        );

    return Promise.all(results);
};

甚至不将 catch 子句放在执行程序的调用会捕获 badFun 错误以外的其他任何内容。

Not even placing the catch clause in the executor's call catches anything else other than the badFun errors.

executor()
    .catch(error => console.log("Failed miserably to catch error!"));



代码



Code

let goodFun = (fruit) => {
  return `I like ${fruit}`;
};

let badFun = (fruit) => {
  throw `${fruit} is spoiled!`;
};

let badPromise = (fruit) => Promise.resolve().then(() => {
  throw `Promise failed with ${fruit}`;
});

let goodPromise = (fruit) => Promise.resolve().then(() => {
  return `Promise succeded with ${fruit}`;
});

let executeSafe =
  (fun, ...args) => Promise.resolve().then(() => {
    return fun(...args);
  });

let asyncFun = (fruit) => Promise.all([badFun, goodFun, badPromise, goodPromise].map(fun => executeSafe(fun, fruit)));

let executor = () => {
  let fruitsArr = ["banana", "orange", "apple"];
  let results = [];

  for (let fruit of fruitsArr)
    results.push(
      asyncFun(fruit)
      .then(res => {
        console.log(res);
      })
      .catch(error => {
        console.log(`Error: ${error}`);
      })
    );

  return Promise.all(results);
};

executor()
  .catch(error => console.log("Failed miserably to catch error!"));

问题:


  • 如何修复我的代码,以便其 then catch 子句在 asyncFun 中起作用

  • How to fix my code so that its then and catch clauses in asyncFun work as intended?

推荐答案

这里的问题是您误会了 Promise.all()有效。它的工作方式是,如果 all 的所有Promise成功,它将解析为一组值。如果其中的任何失败,它将以发生的第一个错误拒绝。

The problem here is that you are misunderstanding how Promise.all() works. The way it works is that if all of the promises succeed, it resolves to an array of values. If any of them fail, it rejects with the first error that occurred.

您似乎期望的是,成功的被困在然后中,而失败的被捕获在 catch 中是不可能的。一个承诺要么解决一次,要么拒绝一次。它不会同时执行两项操作,也不会多次执行。 Promise.all()返回一个诺言,因此它将解决或拒绝。

What you seem to be expecting, that the successful ones are caught in the then and the failed ones are caught in the catch, is not possible. A promise either resolves once or it rejects once. It doesn't do both, and it won't do one or the other multiple times. Promise.all() returns a single promise so it will either resolve or reject.

第三方诺言库可以有一些方法可以解决一系列诺言-基本上要等到它们都完成了自己的任务(成功或失败),然后解决一系列结果。您可以像这样实现它:

Third party promise libraries do have methods for "settling" an array of promises - basically waiting until they have all done their thing (succeeded or failed), and resolving to an array of the results. You can implement it like this:

// values is an array of promises and/or non-promise values
function allSettled(values) {
  let settle =
    value => Promise.resolve(value)
    .then(result => ({ state: "fulfilled", value: result }))
    .catch(error => ({ state: "rejected", reason: error }));

  return Promise.all(values.map(settle));
}

// example usage
allSettled(['hello', 'goodbye', Promise.resolve('good'), Promise.reject('bad')])
  .then(results => console.log(results));

然后您可以像下面一样使用它。

Then you can use it like below.

在不相关的说明中,我还修改了您的方法,因此您不需要修改后的 executeSave 需要 ... args (我认为这是一种复杂的解决方法)。您可以创建使用参数 before 的函数,然后将它们传递给 _executeSafe _

On an unrelated note, I've also modified your approach so that you don't need the modified version of executeSave that takes ...args (I think that's a convoluted way to go about it). You can create functions that use the arguments before you pass them into _executeSafe_:

let goodFun = (fruit) => `I like ${fruit}`;

let badFun = (fruit) => {
  throw `${fruit} is spoiled!`;
};

let badPromise = (fruit) => Promise.reject(`Promise failed with ${fruit}`);

let goodPromise = (fruit) => Promise.resolve(`Promise succeeded with ${fruit}`);

let executeSafe = fun => Promise.resolve().then(fun);

function allSettled(values) {
  let settle = 
    value => Promise.resolve(value)
      .then(result => ({ state: "fulfilled", value: result }))
      .catch(error => ({ state: "rejected", reason: error }));

  return Promise.all(values.map(settle));
}

let asyncFun =
  (fruit) =>
    allSettled([badFun, goodFun, badPromise, goodPromise]
      .map(fun => () => fun(fruit))
      .map(executeSafe)
    );

asyncFun("orange").then(results => console.log(results));

附加说明-如果需要要使用Jared Smith的答案中的 promisify 函数,则可以将 asyncFun 函数更改为此:

Additional side note - if you wanted to use the promisify function from Jared Smith's answer, then you could change your asyncFun function to this:

let asyncFun =
  (fruit) =>
    allSettled([badFun, goodFun, badPromise, goodPromise]
      .map(promisify)
      .map(fun => fun(fruit))
    );

这篇关于然后承诺并且catch子句不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆