async 的语法糖 函数是如何捕获异常的?——大佬间文章矛盾

发布于 2022-09-12 04:30:51 字数 1681 浏览 22 评论 0

async 函数的实现,就是将 Generator 函数和自动执行器,包装在一个函数里。

async function fn(args){
  // ...
}

// 等同于

function fn(args){ 
  return spawn(function*() {
    // ...
  }); 
}

function spawn(genF) {
  return new Promise(function(resolve, reject) {
    var gen = genF();
    function step(nextF) {
      try {
        var next = nextF();
      } catch(e) {
        return reject(e); 
      }
      if(next.done) {
        return resolve(next.value);
      } 
      Promise.resolve(next.value).then(function(v) {
        step(function() { return gen.next(v); });      
      }, function(e) {
        step(function() { return gen.throw(e); });
      });
    }
    step(function() { return gen.next(undefined); });
  });
}

摘自 http://www.ruanyifeng.com/blog/2015/05/async.html

没想明白 spawn 里的catch 什么情况下才会执行了?
和 async await 一样的效果吗?

下面是 async await 捕获异常的写法。
摘自:https://segmentfault.com/a/1190000019854513

async function run() {
    // 这里return 和 await 都可以
    return Promise.reject(new Error("Oops!"));
}
run()
    .catch(function handleError(err) {
        err.message; // Oops!
    })
    .catch(err => {
        process.nextTick(() => {
            throw err;
        });
    });

矛盾来了:

为什么我把 run 写成 上面 generator的形式。没有同样的效果?

function run(args){ 
  return spawn(function*() {
     return Promise.reject(new Error("Oops!"));
  }); 
}
run()
    .catch(function handleError(err) {
        err.message; // Oops!
    })

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

一笑百媚生 2022-09-19 04:30:51
  1. 首先我们知道你传递给 new Promise 的函数是会立即执行的,也就是说你传递给 spawn 的 generator 会立即实例化得到 gen ,也就是第三行 var gen = genF();
  2. 接下来是一个 step 函数声明,先越过去,看到底下立即调用了 step 还给了一个匿名函数当参数。
  3. step 内部上来就是一个 try-catch 包住的 nextFn 调用,来到了题主关注的地方。那么这个 try-catch 捕获的是什么呢?是 nextFn 内部的异常。
  4. nextFn 实际是什么?纵观整个 spawn 函数,nextFn 可能的实参内部调用的东西就两种,gen.next gen.throw。也就是说,try-catch 捕获的就是这两个操作中可能抛出的异常。
  5. gen.next gen.throw 是什么?这你就需要复习一下 Generator 的知识了。
  6. 简单讲,Generator 就是一个可以执行到中途不继续执行,外部戳一下再继续走的函数。简单的类比就是报数,比如每报一个数停一次,外面的人叫你报下一个就是 gen.next,你用 yield value 就是往外报数,外面的人能拿到你报的数 next.value,也能判断出你有没有结束 next.done。如果觉得你报的数有问题,就用 next.throw 告诉你这个报的数有问题你要处理下。
  7. 因此 spawn 中 catch 到的错误是 genF中每次从报上一个数(或最开始)到报下一个数中可能抛出的异常,即两次 yield 之间执行的代码;以及如果出错了,错误交给你后你在处理错误的过程中可能犯的二次错误。
  8. 这个和原生的 async-await 是保持了行为一致的。
冷夜 2022-09-19 04:30:51

@will 那下面 g.throw ('出错了')后, 第二个catch 为什么捕获不到 ?

function* gen(x){
  try {
    var y = yield x + 2;
  } catch (e){ 
    console.log(1,e);
  }
  return y;
}

var g = gen(1);
g.next();

try{
   g.throw ('出错了'); 
} catch (e){ 
  console.log(2,e);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文