首页 文章

如何在async / await情况下正确实现错误处理

提问于
浏览
5

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

我现在不知道如何正确捕获并抛出错误 . 我有多个异步/等待函数,如果在某个地方发生严重错误,我想把错误抛到顶部和所有异步函数并停止执行该函数 .

我试图从异步/ await函数中抛出异常并在目标函数中捕获它,但我在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:未处理的承诺拒绝(拒绝ID:1):错误:未定义getSessionID响应(节点:13964)[DEP0018]弃用警告:不推荐使用未处理的承诺拒绝 . 将来,未处理的承诺拒绝将使用非零退出代码终止Node.js进程 . 附加调试器 .

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

那么我该如何使用呢?我是否应该在异步函数中捕获错误并在promise中返回错误并重新抛出异步函数?

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;}
}

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

我希望有人可以启发我 .

关心Ruvi

编辑基本调用堆栈伪代码:

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; }
   }

1 回答

  • 12

    关于 async / await 的一个好处是,它们使 try / catch 能够使用您的异步代码 .

    你的第一个 basicAuthLogin 函数是绝对正常的(假设 getSessionID 是一个同步函数;如果不是,你就错过了等待[你现在已经说过了]) . 使用 basicAuthLogin 的代码必须处理它将抛出的可能性(通过处理错误或允许它传播给它负责处理它的调用者) . 所以要么:

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

    要么

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

    如果使用它的代码执行这两件事之一(或者让错误传播到执行这两件事之一的代码),则不会出现“未处理拒绝”错误 .

    回应我的评论,询问 getSessionID 是否是异步的,你写道:

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

    Here's a live example 这样做(在我的情况下,我让 basicAuthLogin 实际上使用了 getSessionID 之前的异步,但它并不重要):

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

    该规则与异常一样(因为从概念上讲这些是异常):

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

    • 顶级必须处理它

    规则#2意味着当您从非_852998_代码转换为 async 代码(通常位于堆栈顶部)时,您需要一个包装器 . 或者:

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

    要么

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

    当然还是:

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

    共同点是:顶级总是处理错误 .

相关问题