在Array#map中处理async / await中的错误(拒绝) [英] Handling Errors (Rejections) in async/await inside Array#map

查看:140
本文介绍了在Array#map中处理async / await中的错误(拒绝)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

节点8.1.2,我有一个结构,其中一个文件在地图中调用另一个文件的功能。在一个真实的例子中,我会在地图上使用 Promise.all ,但这不是问题。结构如下:



A.js:

  const {b} = require('./ B')

函数expressStuff(req,res,next){
things.map( thing => {
返回b(东西)
}))

返回res.status(200).json(...)
}

B.js:

  // Thing  - >无极<对象> 
函数b(东西){
返回ThingModel.update(...)//这会返回一个Promise但是FAILS并抛出一个错误的
}

模块。 exports = {b}

好的。所以在函数 b 中我尝试获取一些异步数据(来自数据库)。它失败并抛出一个未被捕获的承诺拒绝。



如何处理它?<​​/ p>

我试过多个解决方案:



A1.js:

  const {b} = require('./ B')

函数expressStuff(req,res,next){
things.map(thing => {
try {
return b(thing)
} catch(err){
return next(err)
}
}))

返回res.status(200).json(...)
}

但这仍未被捕获。



A2.js

  const {b} = require('./ B')

函数expressStuff(req,res,next){

try {
things.map(thing => {
return b(thing)
}))
} catch(err){
return next(err)
}

返回res.status(200).json(...)
}

仍未处理。我尝试使用 Promise.all ,我尝试了双重try-catch块(因为我认为 map 中的那个可能是返回下一步地图结果而不是实际来自 expressStuff function。仍然没有。



我得到答案的关闭是处理错误但是代码不会等待它被抛出而且 res.status() next 会导致竞争条件,在发送后无法设置标头错误。



我想做的就是用函数 b 抛出一个错误,但在 expressStuff 中捕获它,所以我可以重新抛出自定义 UnprocessableEntityError 并将其传递给 。似乎文件 B 中的错误没有冒泡到地图所在的地方被叫。



我该怎么做?



编辑:



我可以做这个rej的唯一方法处理的是在 B.js 中尝试捕获它。但是,如果我试图重新抛出错误/返回它 - 没有。误吞了。如果我尝试 console.log 它 - 它将被记录。



DETAILS:



由于标记的答案,我重构了我的实际代码并使其完美运行。

  function expressStuff(res,req,next){
try {
await Promise.all(things.map(async thing => {
if(ifSomething()){
await b(thing)
}
}))
} catch(错误){
返回下一个(新的MyCustomError('我的自定义错误消息'))
}

返回res.status(200).json(...)
}


解决方案

使用处理拒绝尝试 / catch 仅适用 async function 当你等待承诺时 - 你还没有尝试过。



你可以做任何一个

 异步函数expressStuff(req,res,next){
var结果;
try {
results = await Promise.all(things.map(b)); //当任何承诺拒绝时抛出
} catch(错误){
返回下一个(错误)//处理错误
}
返回res.status(200).json (...)
}

或(如等待所有ES6承诺完成,甚至拒绝承诺

  function expressStuff(req,res,next){
const resultPromises = things.map(async(thing)=> {
尝试{
返回await b(thing); //当这个特殊事物的承诺拒绝
} catch时抛出(错误){
返回defaultValue; //处理错误 - 不要调用`next` here
}
});
...
返回res.status(200).json(...)
}


Node 8.1.2, I have a structure where one file is calling another file's function in a map. In a real example I would use Promise.all on the map but that's not the question here. Here is the structure:

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 }

OK. So in function b I try to get some async data (from a database). It fails and throws an Uncaught Promise Rejection.

How to make deal with it?

I tried multiple solutions:

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(...)
}

But that is still uncaught.

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(...)
}

Still unhandled. I tried using Promise.all, I tried double try-catch blocks (since I thought the one inside map might be returning next from the to the map result and not actually from expressStuff function. Still nothing.

The closes I got to the answer was handling the error but then code wouldn't wait for it to be thrown and both res.status() and next would work resulting in race conditions and cannot set headers after they are sent errors.

All I want to do is for the function b to throw an error but catch it in the expressStuff so I can rethrow custom UnprocessableEntityError and pass it to next. It seems like error from file B is not bubbling up to the map where it is called.

How do I do it?

EDIT:

The only way I can make this rejection handled is try-catching it in the B.js. But if I try to rethrow an error/return it - nothing. Error is swallowed. If I try to console.log it - it will be logged though.

DETAILS:

Thanks to marked answer I refactored my actual code and made it to work perfectly.

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(...)
}

解决方案

Handling rejections with try/catch works only in async functions when you await the promise - which you haven't attempted yet.

You could do either

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(...)
}

or (like 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(...)
}

这篇关于在Array#map中处理async / await中的错误(拒绝)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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