首页 文章

使用async / await尝试/捕获块

提问于
浏览
65

我正在深入研究节点7异步/等待功能,并在这样的代码中保持绊脚石

async function main() {
  try {
    var quote = await getQuote();
    console.log(quote);
  } catch(error) {
    console.error(error);
  }
}

这似乎是使用async / await解析/拒绝或返回/抛出的唯一可能,但是,v8不会优化try / catch块中的代码?!

还有替代品吗?

5 回答

  • 72

    替代类似于Golang中的错误处理

    因为async / await使用了底层的promises,你可以编写一个像这样的小实用函数:

    export function catchEm(promise) {
      return promise.then(data => [null, data])
        .catch(err => [err]);
    }
    

    然后在需要捕获一些错误时导入它,并包装异步函数,该函数返回一个promise .

    import catchEm from 'utility';
    
    async performAsyncWork() {
      const [err, data] = await catchEm(asyncFunction(arg1, arg2));
      if (err) {
        // handle errors
      } else {
        // use data
      }
    }
    
  • 10

    替代品

    替代方案:

    async function main() {
      try {
        var quote = await getQuote();
        console.log(quote);
      } catch (error) {
        console.error(error);
      }
    }
    

    会是这样的,明确地使用promises:

    function main() {
      getQuote().then((quote) => {
        console.log(quote);
      }).catch((error) => {
        console.error(error);
      });
    }
    

    或类似的东西,使用延续传递样式:

    function main() {
      getQuote((error, quote) => {
        if (error) {
          console.error(error);
        } else {
          console.log(quote);
        }
      });
    }
    

    原始示例

    您的原始代码所做的是暂停执行并等待 getQuote() 返回的承诺结算 . 然后它继续执行并将返回的值写入 var quote ,然后在promise被解析时打印它,或者抛出异常并运行catch块,如果promise被拒绝则打印错误 .

    您可以直接使用Promise API执行相同的操作,就像在第二个示例中一样 .

    表现

    现在,为表现 . 我们来试试吧!

    我刚刚写了这段代码 - f1() 给出 1 作为返回值, f2() 抛出 1 作为例外:

    function f1() {
      return 1;
    }
    
    function f2() {
      throw 1;
    }
    

    现在让我们调用相同的代码数百万次,首先使用 f1()

    var sum = 0;
    for (var i = 0; i < 1e6; i++) {
      try {
        sum += f1();
      } catch (e) {
        sum += e;
      }
    }
    console.log(sum);
    

    然后让我们将_622249改为 f2()

    var sum = 0;
    for (var i = 0; i < 1e6; i++) {
      try {
        sum += f2();
      } catch (e) {
        sum += e;
      }
    }
    console.log(sum);
    

    这是我为 f1 得到的结果:

    $ time node throw-test.js 
    1000000
    
    real    0m0.073s
    user    0m0.070s
    sys     0m0.004s
    

    这就是我为 f2 所得到的:

    $ time node throw-test.js 
    1000000
    
    real    0m0.632s
    user    0m0.629s
    sys     0m0.004s
    

    看起来你可以在一个单线程进程中做一两次抛出一秒钟的事情 . 如果你做的不止于此,你可能需要担心它 .

    摘要

    我不担心Node中的那些东西 . 如果这样的事情得到了很多使用,那么它最终将由V8或SpiderMonkey或Chakra团队进行优化,每个人都会遵循 - 它不像它没有被优化为原则,它只是不是问题 .

    即使它仍然没有争论,如果你're maxing out your CPU in Node then you should probably write your number crunching in C - that' s本机插件的用途,除其他外 . 或者像node.native这样的东西比Node.js更适合这份工作 .

    我想知道什么是需要抛出这么多异常的用例 . 通常抛出异常而不是返回值是一个例外 .

  • 8

    try-catch块的替代方法是await-to-js lib . 我经常使用它 . 例如:

    import to from 'await-to-js';
    
    async function main(callback) {
        const [err,quote] = await to(getQuote());
    
        if(err || !quote) return callback(new Error('No Quote found');
    
        callback(null,quote);
    
    }
    

    与try-catch相比,此语法更清晰 .

  • 9
    async function main() {
      var getQuoteError
      var quote = await getQuote().catch(err => { getQuoteError = err }
    
      if (getQuoteError) return console.error(err)
    
      console.log(quote)
    }
    

    或者,您可以执行以下操作,而不是声明可能的var以在顶部保存错误

    if (quote instanceOf Error) ...
    

    虽然如果抛出类似TypeError或Reference错误的东西,这将不起作用 . 你可以确保它是一个常规错误

    async function main() {
      var quote = await getQuote().catch(err => {
        console.error(err)      
    
        return new Error('Error getting quote')
      })
    
      if (quote instanceOf Error) return quote // get out of here or do whatever
    
      console.log(quote)
    }
    

    我对此的偏好是将所有内容包装在一个大的try-catch块中,其中创建了多个promise可能会使得处理特定于创建它的promise的错误变得很麻烦 . 替代方案是多个try-catch块,我觉得同样麻烦

  • 1

    我想这样做:)

    const sthError = () => Promise.reject('sth error');
    
    const test = opts => {
      return (async () => {
    
        // do sth
        await sthError();
        return 'ok';
    
      })().catch(err => {
        console.error(err); // error will be catched there 
      });
    };
    
    test().then(ret => {
      console.log(ret);
    });
    

    它类似于使用 co 处理错误

    const test = opts => {
      return co(function*() {
    
        // do sth
        yield sthError();
        return 'ok';
    
      }).catch(err => {
        console.error(err);
      });
    };
    

相关问题