如何在 async/await 情况下正确实现错误处理 [英] How to properly implement error handling in async/await case

查看:18
本文介绍了如何在 async/await 情况下正确实现错误处理的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用 async/await ecma6 标准,没有任何自定义库.

我目前不知道如何正确捕获和抛出错误.我有多个 async/await 函数,如果发生低于严重错误的某个地方,我想将错误抛出到所有异步函数的顶部并停止执行该函数.

我尝试从 async/await 函数中抛出异常并在目标函数中捕获它,但在 node.js 中出现错误:

 this.basicAuthLogin= 异步函数(用户){严格使用";const login = new Login(this.host, this.url, user, user.pw);//getSessionID 抛出错误this.sessionID = getSessionID(result.request.response);}

<块引用>

(node:13964) UnhandledPromiseRejectionWarning:未处理的承诺拒绝(拒绝 ID:1):错误:getSessionID 响应未定义(节点:13964)[DEP0018] 弃用警告:未处理的承诺拒绝被弃用.在未来,承诺拒绝是未处理将以非零退出终止 Node.js 进程代码.附加调试器.

所以似乎我不允许从异步函数中抛出异常,甚至不允许在 node.js 中 promise 的 catch 块中重新抛出它?

那么我该如何让它工作呢?我是否应该捕获异步函数中的错误并返回承诺中的错误,然后重新抛出异步函数?

 this.basicAuthLogin= 异步函数(用户){严格使用";const login = new Login(this.host, this.url, user, user.pw);尝试{//getSessionID 抛出错误this.sessionID = getSessionID(result.request.response);} 捕捉(错误){ 返回错误;}}

但这意味着在我的第一个异步函数的调用堆栈中,每个函数都需要异步,即使我真的不需要它,我也必须等待承诺.

希望有人能指教我.

问候茹薇

编辑基本调用栈伪代码:

 async startTest[arr]{for (var i = 0; i < arr.length; i++){尝试 {等待 runStep(arr[i];} 抓住(错误){控制台日志(错误);休息;}}}异步运行步骤(步骤){尝试 {var userIsValid = await validateUser(step.user);var req = buildRequest(step.request);var 结果 = 等待 sendRequest(req);var verify = verifyResult();} 捕捉(错误){ 抛出错误;}}异步验证用户(用户){//进行检查//var result = await this.authenticate(parameter).catch(err => {throw err});用户发现 = 真;}功能认证(参数){//可以抛出异步函数basicAuthLogin(parameter).catch(err => {throw err};}函数 async basicAuthLogin(parameter(){尝试 {//可以抛出异步函数var 结果 = 等待请求(参数);//可以抛出同步函数this.sessionID = getSessionID(响应);//可以抛出同步函数} 捕捉(错误){ 抛出错误;}}

解决方案

async/await 的一大优点是它们启用了 try/catch 以处理您的异步代码.

你的第一个 basicAuthLogin 函数绝对没问题(前提是 getSessionID 是一个 同步 函数;如果不是,你'错过了await [你现在已经说过了]).代码using basicAuthLogin 必须处理它抛出的可能性(通过处理错误或允许它传播到负责处理它的调用者).所以要么:

//在 `async` 函数中尝试 {等待 this.basicAuthLogin(/*...*/);}赶上(e){//处理失败的事实}

//不在 `async` 函数中:this.basicAuthLogin(/*...*/).catch(e => {/* 处理失败的事实 */});

如果使用它的代码执行了这两件事之一(或者让错误传播到执行这两件事之一的代码),您将不会收到未处理的拒绝"错误.

针对我询问 getSessionID 是否异步的评论,您写道:

<块引用>

不,它不是异步的,它是一个简单的函数,它抛出一个异常,我想在调用堆栈上捕获 5 或 6 层,但似乎我不允许这样做.

这是一个活生生的例子(在我的例子中,我已经让 basicAuthLogingetSessionID 之前实际上使用了一些异步的东西,但是这并不重要):

const getSessionID = () =>{抛出新错误(失败");};const somethingAsync = () =>新承诺(解决 => {设置超时(解决,100);});const basicAuthLogin = 异步函数(用户){严格使用";等待某事Async();/*const login = new Login(this.host, this.url, user, user.pw);*///getSessionID 抛出错误getSessionID();};const wrapper1 = async() =>{等待 basicAuthLogin();};const wrapper2 = async() =>{等待包装器1();};const wrapper3 = async() =>{等待包装器2();};//顶级调用者(异步() => {尝试 {等待 wrapper3();}赶上(e){console.log("捕获错误:" + e.message);}})();

规则就像有例外一样(因为理论上这些例外):

  1. 要么处理它(例如,try/catch),要么让它传播给调用者(通常不做任何事情),并且

  2. 顶层必须处理它

规则#2 意味着当您从非async 代码转换到async 代码(通常就在堆栈的顶部)时,您需要一个包装器.要么:

(async() => {尝试 {等待第一异步函数();等待 NextAsyncFunction();等待 aThirdAsyncFunction();}赶上(e){//处理错误}})();

(async() => {等待第一异步函数();等待 NextAsyncFunction();等待 aThirdAsyncFunction();})().catch(e => {/* 处理错误 */});

或者当然:

theFirstAsyncFunction().then(() => theNextAsyncFunction()).then(() => aThirdAsyncFunction()).catch(e => {/* 处理错误 */});

这里的共同点是:顶层总是处理错误.

I use async/await ecma6 standard without any custom library.

I don't get at the moment how I can properly catch and throw errors. I have multiple async/await functions and if somewhere down below an critical error happens I want to throw the error to the top and of all async functions and stop execution of the function.

I tried to throw exceptions out of the async/await function and catch it in the target function but I get a error in node.js:

    this.basicAuthLogin= async function(user)
{
    "use strict";
    const login = new Login(this.host, this.url, user, user.pw);

    //getSessionID throws error
    this.sessionID = getSessionID(result.request.response);
}

(node:13964) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: getSessionID response is undefined (node:13964) [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. Debugger attached.

So it seems I am not allowed to throw exceptions out of async functions or even rethrow it in the catch block of the promise in node.js?

So how do I get this working? Am I supposed to catch the error in the async function and return the error in the promise and rethrow then out of the async function?

   this.basicAuthLogin= async function(user)
{
    "use strict";
    const login = new Login(this.host, this.url, user, user.pw);
   try{
    //getSessionID throws error
    this.sessionID = getSessionID(result.request.response);
   } catch(err) { return err;}
}

But this would mean that in my call stack from the first async function every function needs be async and I have to await the promise even though I don't really need it.

I hope somebody can enlighten me.

Regards Ruvi

Edit basic call stack pseudo code:

   async startTest[arr]{

    for (var i = 0; i < arr.length; i++)
    {
      try {
          await runStep(arr[i];
        } catch(err) { 
            console.log(err);
            break; 
        }
      }
    }

  async runStep(step)
  {
     try {
     var userIsValid = await validateUser(step.user);
     var req = buildRequest(step.request);
     var result = await sendRequest(req);
     var verify = verifyResult();
     } catch(err){ throw err;}
  }

  async validateUser(user)
  {
     //make checks
     //
     var result = await this.authenticate(parameter).catch(err => {throw err});
     userFound = true;
   }

  function authenticate(parameter) {
  //can throw async function
   basicAuthLogin(parameter).catch(err => {throw err};

   }

  function async basicAuthLogin(parameter()
  {
   try {
    //can throw  async function
      var result = await request(parameter);
      //can throw sync function
      this.sessionID = getSessionID(response);
      //can throw   sync function
      } catch(err) { throw err; }
   }

解决方案

One of the great things about async/await is that they enable try/catch to work with your asynchronous code.

Your first basicAuthLogin function is absolutely fine (provided getSessionID is a synchronous function; if it isn't, you're missing an await [you've now said it is]). The code using basicAuthLogin must handle the possibility it will throw (either by handling the error or allowing it to propagate to its caller, which is responsible for handling it). So either:

// In an `async` function
try {
    await this.basicAuthLogin(/*...*/);
} catch (e) {
    // Handle the fact something failed
}

or

// NOT in an `async` function:
this.basicAuthLogin(/*...*/)
    .catch(e => { /* Handle the fact something failed */ });

If the code using it does one of those two things (or lets the error propagate to code that does one of those two things), you won't get the "Unhandled rejection" error.

In response to my comment asking if getSessionID was asynchronous, you wrote:

No it is not async it is a simple function that throws an exception that I want to catch 5 or 6 floors up the call stack but it seems I am not allowed to do that.

Here's a live example of doing that (in my case, I've made basicAuthLogin actually use something asynchronous prior to getSessionID, but it doesn't really matter):

const getSessionID = () => {
  throw new Error("Failed");
};
const somethingAsync = () => new Promise(resolve => {
  setTimeout(resolve, 100);
});
const basicAuthLogin = async function(user)
{
    "use strict";
    await somethingAsync();
    /*
    const login = new Login(this.host, this.url, user, user.pw);
    */

    //getSessionID throws error
    getSessionID();
};

const wrapper1 = async () => {
  await basicAuthLogin();
};
const wrapper2 = async () => {
  await wrapper1();
};
const wrapper3 = async () => {
  await wrapper2();
};

// Top-level caller
(async () => {
  try {
    await wrapper3();
  } catch (e) {
    console.log("Caught error: " + e.message);
  }
})();

The rule is just like it is with exceptions (because notionally these are exceptions):

  1. Either handle it (e.g., try/catch), or let it propagate to the caller (typically by not doing anything at all), and

  2. The top level MUST handle it

That Rule #2 means that when you transition from non-async code to async code (typically right at the top of your stack), you need a wrapper. Either:

(async () => {
  try {
    await theFirstAsyncFunction();
    await theNextAsyncFunction();
    await aThirdAsyncFunction();
  } catch (e) {
    // handle the error
  }
})();

or

(async () => {
  await theFirstAsyncFunction();
  await theNextAsyncFunction();
  await aThirdAsyncFunction();
})().catch(e => { /* handle the error */});

or of course:

theFirstAsyncFunction()
.then(() => theNextAsyncFunction())
.then(() => aThirdAsyncFunction())
.catch(e => { /* handle the error */});

The common denominator there is: The top level always handles the error.

这篇关于如何在 async/await 情况下正确实现错误处理的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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