try catch 捕获异步的问题

场景:最近在做表单验证 发现了很多的form表单验证的时候很多都是采用的异步捕获?我依稀记得try catch 是捕获同步代码的错误机制,为什么可以捕获到异步的操作;以下是截取antDesign一段伪代码
image.png

可以参考 下方的伪代码:

  const result = () => {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          reject('我是错误')
        }, 1000)
      })
    }

      async function foo () {
          try{
            const  m = await result()
          }catch(error){
            console.log(error,'9999')
          }
      };
      foo()

问题:为什么可以捕获?这其中的原理是什么?是否只要带上await 的语法糖都是用try catch 进行捕获?

阅读 3.2k
2 个回答

try catch 能捕获 async函数中await的异步异常,是基于类es6 generator生成器函数的调度机制。

除开async await是一些现代浏览器或者高版本node已经原生支持的不说。可以通过babel 将async await 编译成es5来透析它的ployfill实现。generator主要是两种调度类型,nextthrow generator上有一个throw就是原声的throw方法

eg. 在https://babeljs.io/repl将以下代码转换,然后自行断点调试

function mockAsyncError(){
  return new Promise((resolve,reject)=>{
    setTimeout(()=>{
        reject("一个异步error")
    },2000)
  })
}

async function test(){
  try{
    console.log(1)
    await mockAsyncError()
  }catch(e){
    console.log("e",e)
  }
   
}
test()
// 转换为generator
"use strict";

function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }

function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }

function mockAsyncError() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      reject();
    }, 2000);
  });
}

function test() {
  return _test.apply(this, arguments);
}

function _test() {
  _test = _asyncToGenerator(function* () {
    try {
      console.log(1);
      yield mockAsyncError();
    } catch (e) {
      consol.log("e", e);
    }
  });
  return _test.apply(this, arguments);
}

test();
// es5版本
"use strict";

function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }

function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }

function mockAsyncError() {
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      reject();
    }, 2000);
  });
}

function test() {
  return _test.apply(this, arguments);
}

function _test() {
  _test = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee() {
    return regeneratorRuntime.wrap(function _callee$(_context) {
      while (1) {
        switch (_context.prev = _context.next) {
          case 0:
            _context.prev = 0;
            console.log(1);
            _context.next = 4;
            return mockAsyncError();

          case 4:
            _context.next = 9;
            break;

          case 6:
            _context.prev = 6;
            _context.t0 = _context["catch"](0);
            consol.log("e", _context.t0);

          case 9:
          case "end":
            return _context.stop();
        }
      }
    }, _callee, null, [[0, 6]]);
  }));
  return _test.apply(this, arguments);
}

test();

就是语言本身的能力啊
在async function里try await的promise,就能把promise的异常捕获了

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题