当前位置: 首页 > 面试题库 >

JavaScript等到所有诺言都完成,即使有些诺言被拒绝

阮轶
2023-03-14
问题内容

假设我有一组Promise正在发出网络请求的,其中一个会失败:

// http://does-not-exist will throw a TypeError
var arr = [ fetch('index.html'), fetch('http://does-not-exist') ]

Promise.all(arr)
  .then(res => console.log('success', res))
  .catch(err => console.log('error', err)) // This is executed

假设我要等到所有这些完成为止,无论是否失败。我无法使用的资源可能会出现网络错误,但是如果可以得到,我需要在继续之前进行此操作。我想优雅地处理网络故障。

既然Promises.all没有任何余地,那么在不使用Promise库的情况下,推荐的处理方式是什么?


问题答案:

解决此问题的明确方法是简单地调用.catch内部promise,然后从其回调中返回错误。

let a = new Promise((res, rej) => res('Resolved!')),
    b = new Promise((res, rej) => rej('Rejected!')),
    c = a.catch(e => { console.log('"a" failed.'); return e; }),
    d = b.catch(e => { console.log('"b" failed.'); return e; });

Promise.all([c, d])
  .then(result => console.log('Then', result)) // Then ["Resolved!", "Rejected!"]
  .catch(err => console.log('Catch', err));

Promise.all([a.catch(e => e), b.catch(e => e)])
  .then(result => console.log('Then', result)) // Then ["Resolved!", "Rejected!"]
  .catch(err => console.log('Catch', err));

更进一步,您可以编写一个通用的catch处理程序,如下所示:

const catchHandler = error => ({ payload: error, resolved: false });

那你可以做

> Promise.all([a, b].map(promise => promise.catch(catchHandler))
    .then(results => console.log(results))
    .catch(() => console.log('Promise.all failed'))
< [ 'Resolved!',  { payload: Promise, resolved: false } ]

这样做的问题在于,捕获的值将具有与非捕获的值不同的接口,因此要清理此问题,您可以执行以下操作:

const successHandler = result => ({ payload: result, resolved: true });

现在,您可以执行以下操作:

> Promise.all([a, b].map(result => result.then(successHandler).catch(catchHandler))
    .then(results => console.log(results.filter(result => result.resolved))
    .catch(() => console.log('Promise.all failed'))
< [ 'Resolved!' ]

然后将其保持干燥,您会得到本杰明的答案:

const reflect = promise => promise
  .then(successHandler)
  .catch(catchHander)

现在看起来像什么

> Promise.all([a, b].map(result => result.then(successHandler).catch(catchHandler))
    .then(results => console.log(results.filter(result => result.resolved))
    .catch(() => console.log('Promise.all failed'))
< [ 'Resolved!' ]

第二个解决方案的好处是抽象和DRY。不利的一面是您拥有更多的代码,并且必须记住要体现所有使事情保持一致的承诺。

我将我的解决方案描述为显式和KISS,但确实不够可靠。该界面不能保证您确切知道承诺是成功还是失败。

例如,您可能有以下内容:

const a = Promise.resolve(new Error('Not beaking, just bad'));
const b = Promise.reject(new Error('This actually didnt work'));

这不会被抓住a.catch,所以

> Promise.all([a, b].map(promise => promise.catch(e => e))
    .then(results => console.log(results))
< [ Error, Error ]

无法判断哪个是致命的,哪个不是。如果这很重要,那么您将需要实施和接口以跟踪是否成功(reflect确实如此)。

如果您只想优雅地处理错误,则可以将错误视为未定义的值:

> Promise.all([a.catch(() => undefined), b.catch(() => undefined)])
    .then((results) => console.log('Known values: ', results.filter(x => typeof x !== 'undefined')))
< [ 'Resolved!' ]

就我而言,我不需要知道错误或失败的方式,我只是在乎我是否有价值。我将让生成promise的函数担心记录特定错误。

const apiMethod = () => fetch()
  .catch(error => {
    console.log(error.message);
    throw error;
  });

这样,应用程序的其余部分可以根据需要忽略其错误,并在需要时将其视为未定义的值。

我希望我的高级函数能够安全地失败,而不必担心其依赖项失败的原因的细节,并且在必须进行权衡时,我也更喜欢KISS而不是DRY,这最终就是为什么我选择不使用reflect



 类似资料:
  • 假设我有一组正在发出网络请求的,其中一个将失败: 假设我想等到所有这些都完成了,不管有没有一个失败了。可能有一个网络错误的资源,我可以生存没有,但如果我可以获得,我想要在我继续。我想优雅地处理网络故障。 由于没有为此留出任何空间,那么在不使用promissions库的情况下,处理此问题的推荐模式是什么?

  • 问题内容: 因此,我遇到了多个未知长度的promise链的情况。我希望在处理所有链条后执行一些操作。那有可能吗?这是一个例子: 在此示例中,我设置了一个承诺1,,2和3,这些承诺会在某个随机时间得到解决。然后,我将诺言添加到第一和第三的结尾。我想在所有链条都解决后解决。这是运行此代码时的输出: 有没有办法等待连锁解决? 问题答案: 当所有链条都解决后,我希望所有人解决。 当然,然后将每个链的承诺传

  • 问题内容: 我目前正在等待所有承诺按顺序完成,如下所示: 但是,通过这种方式,配置文件和令牌将顺序执行。由于两者彼此独立,因此我希望两者一起独立执行。我认为可以使用Promise.all完成此操作,但是我不确定语法,也找不到任何帮助。 所以我的问题是如何转换上面的api调用以一起运行,然后返回最终输出。 问题答案:

  • 问题内容: 有任何想法吗?为什么节点说“文件名未定义”?谢谢。合同,政策和发票功能不使用任何数据进行解析,仅使用resolve()。 问题答案: 首先,您不能写: (如果该函数返回 另一个 函数充当处理程序,则可以使用) 您必须写: 要么: 或者,如果一个函数应该处理其他函数的结果,则可能是这样: 作为参数传递给您的是函数,而不是调用函数的结果(在您的示例中这可能是一个承诺)。 我不知道这是否是您

  • 问题内容: 我在理解为什么拒绝不通过承诺链传递时遇到问题,我希望有人能够帮助我理解原因。对我来说,将功能附加到承诺链上意味着我有意要实现的原始承诺。很难解释,所以让我先显示我的问题的代码示例。(注意:此示例使用的是Node和延迟的节点模块。我使用Dojo 1.8.3对此进行了测试,并得到了相同的结果) 运行此操作的结果是以下输出: 好吧,对我来说,这个结果没有意义。通过附加到这个承诺链,每个人都暗

  • 问题内容: 我读到用关键字标记的异步函数隐式返回一个promise: 但这不连贯…假设返回一个诺言,而await关键字将从诺言中返回值,而不是诺言itsef,那么我的getVal函数 应该 返回该值,而不是隐式诺言。 那到底是什么情况?用async关键字标记的函数是隐式返回promise还是控制它们返回的内容? 也许,如果我们不明确地返回某些东西,那么他们会隐式地返回一个诺言…? 更清楚地说,上述