V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a JavaScript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
JavaScript 权威指南第 5 版
Closure: The Definitive Guide
yazoox
V2EX  ›  JavaScript

继续请教一下,怎么捕获/try-catch Promise 的 executor 里面的异常?

  •  
  •   yazoox · 2020-09-01 11:12:14 +08:00 · 1328 次点击
    这是一个创建于 1304 天前的主题,其中的信息可能已经有所发展或是发生改变。

    例如,var p = new Promise(...); 这个变量 p 还没有赋值,executor of the promise 就已经开始执行了吧。那么问题来了。如何 try-catch executor 里面的 exception 呢?

    如下所示,如果 调用 p 和 检查并使用 p,分别在不同的函数里面 func3 vs. func4,如何捕获并检查 p 的结果呢?

    func1 或者 func2 throw exception,到底是在 func3 里面被抓还是 func4 里面被抓?有没有什么 better-practice ?

    
    async func1() {
    ...
    ""(); // will throw type error
    }
    
    func2() {
    return new Promise((resolve, reject) => {
    ""(); // will throw type error
    });
    
    
    let p = null;
    func3() {
      p = func1(); // or p = func2();
      
      
      // learn from the stackoverflow
      (async () => {
        await p;
      }).catch(...);
    }
    
    func4() {
      try {
        const res = await p;
      } catch (error) {...}
      send(res);
    }
    

    楼主实际使用的场景在这里: https://v2ex.com/t/701731
    stackoverflow 上面看到的参考: https://stackoverflow.com/questions/43036229/is-it-an-anti-pattern-to-use-async-await-inside-of-a-new-promise-constructor

    5 条回复    2020-09-09 12:41:20 +08:00
    libook
        1
    libook  
       2020-09-02 11:24:38 +08:00
    语法错得有点多,比如 func2 是不是缺括号,以及 4 个 func 是不是函数声明语法(要么用 function 指令,要么用箭头函数)?还有有的函数带 async 、有的不带 async (像 func4 内有 await 是不是外部得有个 async 环境),你写的 func3 内部的 catch 是直接挂在 async function 声明上的,不是挂在 async function 执行结果返回的 promise 上的(两者类型不一样,通常 catch 都会挂在 promise 对象上)。


    按照我的理解硬猜吧,首先先把你的代码调整到正确的语法(回复不支持格式化,你自己贴到文本编辑器里手动格式化一下):
    wrong = "";

    function func0(){
    wrong();
    }

    async function func1() {
    wrong(); // will throw type error
    }

    // 任何时候调用这个函数,都相当于直接创建了一个新 Promise 并立即处于 pending 状态,但第一次 await 之前不会真正执行
    function func2(){
    return new Promise((resolve,reject)=>{
    wrong(); // will throw type error
    });
    }

    let p = null;
    function func3() {
    p = func0();
    //p = func1();
    //p = func2();

    // learn from the stackoverflow
    (async () => {
    console.log('第一次 await,Promise 开始执行');
    await p;
    })().catch(console.log('await 执行产生了 Error'));
    }

    async function func4() {
    p = func0();
    //p = func1();
    //p = func2();

    try {
    console.log('在 try 里执行 await');
    const res = await p;
    } catch (error) {
    console.error('try 捕捉到了 Error');
    }
    }

    你自己分别执行 func3 和 func4,以及分别换 p=func1()和 p=func2(),看看 console 里输出的信息的顺序,可以看到,func3 和 func4 里的 catch 都是能顺利触发的,也就表明错误不是在赋值了 p 的时候就发生的;为了进一步证明这个,我在上面代码里加了一个非异步执行的 func0,你试一试在 func3 和 func4 里给 p 赋值 func0,你会发现 catch 里的信息没有输出,也就是 Error 不是在 await 执行的时候发生的,而是在赋值 p 的时候就发生了。

    func1 和 func2 对于外界调用他们的函数来说两者几乎是等价的,都是返回一个 promise,区别就是在这两个函数内部你希望是以 promise (比如内部调用某些 API 是基于 callback 实现异步执行的)语法还是以 async/await 语法来写。

    另外并不建议 func3 和 func4 中给 p 赋值的写法,因为当你不确定给 p 赋的值是什么类型的时候,如果遇到 func0 的情况就会直接在这里报错,你若希望在下面执行 p 的时候捕捉错误,可以在给 p 赋值函数(去掉括号)而不是函数的调用,如 p=func0;然后在下面执行的时候加上括号 await p();,这样不管你给 p 赋值的是同步还是异步函数,错误都会统一在下面执行的时候捕捉到。

    归根结底还是建议楼主去仔细学习一下 Promise 的原理和执行过程,网上有不少优秀的教程,把 Promise 吃透之后,JS 的异步开发就游刃有余了。

    另外建议楼主多阅读优秀的 JavaScript 项目代码。
    galikeoy
        2
    galikeoy  
       2020-09-08 21:31:55 +08:00
    无论是 promise 还是 async/await 语法,都涉及到一个 event loop,也就是“队列”,这样说对吧,理解 event loop 后你再看 promise 真的很简单,我之前就是这样,感觉一切都透明起来了,(楼主的 js 看的我头晕
    yazoox
        3
    yazoox  
    OP
       2020-09-09 10:07:06 +08:00
    @galikeoy 有相关文档 event loop 讲得比较好的推荐么? thx.
    yazoox
        4
    yazoox  
    OP
       2020-09-09 10:24:55 +08:00
    @libook 谢谢回复。

    “另外并不建议 func3 和 func4 中给 p 赋值的写法,因为当你不确定给 p 赋的值是什么类型的时候,如果遇到 func0 的情况就会直接在这里报错”。
    因为我的需求,就是要把 promise 的执行和检查分离。这也是我弄不清楚的地方,到底应该在哪里 try-catch promise 的 exception.

    主楼帖子里,有个链接,是原始的需求。即,
    启动并执行 promise (收集数据),然后 websocket 同时执行其它操作,比如,发送其它的数据。在 websocket 接收到某信号时,同时检查该数据是否已经准备完毕,比如:await p 。直到准备完毕,则发送数据。这里的 p,我是定义的 class 的 member variable. 这些函数,包括 ruturn promise 函数和 websocket 相关函数,都是成员方法,都能访问这个 p.
    galikeoy
        5
    galikeoy  
       2020-09-09 12:41:20 +08:00
    @yazoox #3 对于你的一个 promise 同时在多处 await 时,哪个会触发,这篇文章可以给你答案 https://segmentfault.com/a/1190000018675871

    然后你的那个帖子 @jiangzm 说的是对的
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   941 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 21:32 · PVG 05:32 · LAX 14:32 · JFK 17:32
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.