处理 Array#map 中的 async/await 中的错误(拒绝)
Posted
技术标签:
【中文标题】处理 Array#map 中的 async/await 中的错误(拒绝)【英文标题】:Handling Errors (Rejections) in async/await inside Array#map 【发布时间】:2017-12-15 03:43:51 【问题描述】:节点 8.1.2,我有一个结构,其中一个文件在映射中调用另一个文件的函数。在一个真实的例子中,我会在map
上使用Promise.all
,但这不是这里的问题。这是结构:
A.js:
const b = require('./B')
function expressStuff (req, res, next)
things.map(thing =>
return b(thing)
))
return res.status(200).json(...)
B.js:
// Thing -> Promise<Object>
function b (thing)
return ThingModel.update(...) // this returns a Promise but FAILS and throws an errror
module.exports = b
好的。所以在函数b
中,我尝试获取一些异步数据(来自数据库)。它失败并抛出 Uncaught Promise Rejection。
如何处理?
我尝试了多种解决方案:
A1.js:
const b = require('./B')
function expressStuff (req, res, next)
things.map(thing =>
try
return b(thing)
catch (err)
return next(err)
))
return res.status(200).json(...)
但这仍然没有被抓住。
A2.js
:
const b = require('./B')
function expressStuff (req, res, next)
try
things.map(thing =>
return b(thing)
))
catch (err)
return next(err)
return res.status(200).json(...)
仍未处理。我尝试使用Promise.all
,我尝试了双重try-catch 块(因为我认为map
内部的那个可能会从next
返回到map
结果,而不是实际上来自expressStuff
函数。仍然没有。
我得到答案的最后是处理错误,但代码不会等待它被抛出,res.status()
和 next
都可以工作,导致竞争条件和 cannot set headers after they are sent
错误。
我想做的只是让函数b
抛出一个错误,但在expressStuff
中捕获它,这样我就可以重新抛出自定义UnprocessableEntityError
并将其传递给next
。似乎来自文件 B
的错误没有冒泡到调用它的 map
。
我该怎么做?
编辑:
我可以处理此拒绝的唯一方法是尝试在B.js
中捕获它。但是,如果我尝试重新抛出错误/返回它 - 什么都没有。错误被吞没。如果我尝试console.log
它 - 它会被记录下来。
详情:
感谢标记的答案,我重构了我的实际代码并使其完美运行。
function expressStuff (res, req, next)
try
await Promise.all(things.map(async thing =>
if (ifSomething())
await b(thing)
))
catch (err)
return next(new MyCustomError('My Custom Error Message'))
return res.status(200).json(...)
【问题讨论】:
【参考方案1】:使用try
/catch
处理拒绝仅适用于async function
s,当您await
承诺时 - 您还没有尝试过。
你也可以
async function expressStuff (req, res, next)
var results;
try
results = await Promise.all(things.map(b)); // throws when any of the promises reject
catch (err)
return next(err) // handle error
return res.status(200).json(...)
或(如Wait until all ES6 promises complete, even rejected promises)
function expressStuff (req, res, next)
const resultPromises = things.map(async (thing) =>
try
return await b(thing); // throws when the promise for this particular thing rejects
catch (err)
return defaultValue; // handle error - don't call `next` here
);
…
return res.status(200).json(...)
【讨论】:
啊,是的。这是一个很好的建议!但是这还是有Can't set headers after they are sent.
的问题,因为return next(err)
和return res.status(200)
都在尝试执行。有什么想法吗?
@TomaszGałkowski 你确定你在同一个函数中有两个返回,就像我的回答一样?
是的,肯定的。这是一个异步函数,awaits
用于一件事,然后再执行该映射。在地图之后它返回 200。如果地图中发生错误,它应该返回 next
并带有我的自定义错误 - 并发送 422。它现在尝试执行此操作,感谢您。但这就是双标头的来源。
你不能在map
回调中调用next
,它可能会在那里发生多次。如果你在next()
之后return
,它不会执行res.status()
。请发布导致错误的更新代码
实际上,最后一条评论让我重新格式化代码并找到错误。我在map
中多了一个if
子句,所以我移动了await Promise.all()
以包含整个地图。我将在问题中发布详细信息并将您的回复标记为答案,因为它完美地回答了我最初的问题。以上是关于处理 Array#map 中的 async/await 中的错误(拒绝)的主要内容,如果未能解决你的问题,请参考以下文章
Array.apply(null,{length:6}).map()