【问题标题】:how to handle errors in multiple async await whle promise rejected without using try catch blocks?如何在不使用 try catch 块的情况下处理多个异步等待中的错误,而 promise 被拒绝?
【发布时间】:2019-05-26 18:43:30
【问题描述】:

我是新来表达的,正在制作用户注册 api。在这个我需要散列用户密码并生成一个随机字符串。这两件事都是由 aync/await 完成的。如果一个承诺被拒绝,那么它会在错误处理中返回响应,但会向我显示未处理的拒绝承诺的警告。

methods.signup = async (req,res,next) => {
    const errors = validationResult(req);
    if (!errors.isEmpty()) {
        return res.status(config.errorCodes.validation).json({errors:errors.array()});
    }
    let payload = req.body;
    var newUser = new User({
        username:payload.username,
        fullname:payload.fullname,
        email: payload.email,
        password: payload.password,
        urltoken:{
            token:null
        },
        actStatus: 0,
        provider: 'email',
       role:1
    });
    let hash = commonMethods.generatePasswordHash(payload.password);
    let token = commonMethods.createRandomString();

    let [a,b] = await Promise.all([hash,token]).catch(err=>{
        res.status(400).json({status:false,msg:"error in promise"})
     });

    newUser.password = a;
    newUser.urltoken.token = b;
    newUser.save(function(err){
        if(err) {
            return res.status(config.errorCodes.success).json({ status:false 
        ,msg:"Error in saving userdata. Please try again",err});
        }
        else {
            commonMethods.sendMail(newUser);
            return res.status(config.errorCodes.success).json({"status":true, 
        "msg":"Registered succesfully. Please Check your Email to verify 
        your account.",newUser})
    }
}); 
}

承诺是 -

commonMethods.createRandomString = function(password){
    return new Promise(function(resolve, reject) {
    var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz";
    var string_length = 25;
    var randomstring = '';
    for (var i=0; i<string_length; i++) {
        var rnum = Math.floor(Math.random() * chars.length);
        randomstring += chars.substring(rnum,rnum+1);
    }
   reject(randomstring);
   // resolve(randomstring);

})
}

总是因为创建错误而被拒绝。

这里是下面的错误

UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 2)
(node:15172) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

如何在不使用 try catch 或 then for promises 的情况下捕获这些错误并保持我的代码简单易读。

【问题讨论】:

    标签: node.js express


    【解决方案1】:

    问题是线条

    let [a,b] = await Promise.all([hash,token]).catch(err=>{
      res.status(400).json({status:false,msg:"error in promise"})
    });
    

    如果hashtoken 抛出,则进入.catch 函数,但catch 函数不返回任何内容:因此,在awaitcatch 完成后,解释器会看到类似

    let [a,b] = undefined
    

    这不起作用(undefined 不可迭代),所以整个 .signup 方法拒绝。如果hashtoken 中出现错误,您需要一些方法让signup 函数的其余部分停止执行,可能类似于

    const result = await Promise.all([hash,token]).catch(err=>{
      res.status(400).json({status:false,msg:"error in promise"})
    });
    if (!result) return;
    let [a,b] = result;
    

    你说你不想使用try/catch,但是这样逻辑可能更容易遵循,因为你可以立即从catch内部return

    let a, b;
    try {
      ([a, b] = await Promise.all([hash,token]));
    } catch(e) {
      return res.status(400).json({status:false,msg:"error in promise"});
    }
    

    【讨论】:

    • 或者如果promise总是返回带有错误属性和数据的解析对象,我们可以试试。然后我们可以检查 a.err && b.err ?哪个编码更好?
    • 在制作 API 时,使用 async/await 还是使用 promise/ .then 哪个更好?因为 async await 使得代码和 promise 变得更清晰、更好地理解/然后使代码变得冗长!
    • 你可以做.catch(err =&gt; err)然后检查result instanceof Error如果你愿意。这取决于你,我没有偏好(尽管我通常在代码风格方面有偏好:))
    • .thens 和awaits 在不同的情况下都可以缩短代码。
    • - 如果我们有依赖的 Promise 链.. 那么我们应该使用 .then 并且如果我们需要带有 Promise 的独立结果,我们可以使用 async/await ?
    【解决方案2】:

    API 编码约定建议

    1) 有两种方法可以巧妙地处理错误。第一个是使用 try catch 块包装所有异步路由,该块将处理同步和异步代码错误。

    异步/等待

    methods.foo = async(req, res, next) => {
    try {
        // assuming bizz is a utility analogous to createRandomString
        // and returns a promise object which will either get resolved or rejected
        // if resolved the response will end in this case and end the response
        // if rejected, await will throw an error which will be caught by the catch block
        var bar = await bizz(); // Asynchronous code(which will wait for a promise to be resolved)
    
        // {... DO SYNCHRONOUS STUFF ...}
    
        // if suppose there is an error in your synchronous code,
        // then it will throw an error which also will  be caught by the catch block
        res.end();
    } catch (err) {
        // {... DO WHAT YOU NEED TO WITH THE ERROR CAUGHT BY EITHER Asynchronous OR Synchronous part of the method ...}
        console.log(err);
        res.end(err);
      }
    }
    

    2) 第二种方法是使用一个中间件来包装所有路由,从而避免为所有路由重写 try catch。这里同步和异步错误都将由异步中间件中的 .catch() 部分处理。

    使用异步等待中间件

    const asyncMiddleware = (asyncFunction) => {
    return (req, res, next) => {
        Promise.resolve(asyncFunction(req, res, next))
        .catch((err) => {
            // DO STUFF WITH ERROR
            res.end(err);
        });
      }
    };
    methods.foo = asyncMiddleware((req, res, next) => {
      // assuming bizz is a utility analogous to createRandomString
      // and returns a promise object which will either get resolved or rejected
      // if resolved the response will end in this case and end the response
      // if rejected, await will throw an error which will be caught by asyncMiddleware
      var bar = await bizz(); // Asynchronous code(which will wait for a promise to be resolved)
    
      // {... DO SYNCHRONOUS STUFF ...}
      // if suppose there is an error in your synchronous code
      // then it will throw an error which also will be caught by asyncMiddleware
      res.end();
    });
    

    【讨论】:

    • 不错。但我不明白第二种方式。!
    • 异步中间件充当每个路由的包装器。例如,如果您的应用程序中有 5 条路由,那么按照第一种方法,我们需要在每条路由的 try catch 块中处理错误。相反,假设我们将它包装在中间件周围。现在,对该路由的每次调用都将由中间件提供服务。所以中间件本身接受一个 asyncFunction ,它本质上是一个快速路由,并将它包装在一个 Promise 中。如果 Promise Rejection 或同步部分在路由中引发了一些错误,则 asyncMiddleware 中的 .catch 部分将处理这两个错误。
    猜你喜欢
    • 2020-12-19
    • 2019-02-28
    • 2012-05-05
    • 2021-01-15
    • 2019-02-11
    • 1970-01-01
    • 2018-05-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多