zoukankan      html  css  js  c++  java
  • 如何在Promise链中共享变量?

    译者按: 使用Promise写过异步代码的话,会发现在Promise链中共享变量是一个非常头疼的问题,这也是Async/Await胜过Promise的一点,我们在Async/Await替代Promise的6个理由有提过,这篇博客将有更详细的介绍。

    为了保证可读性,本文采用意译而非直译,并且对源代码进行了大量修改。另外,本文版权归原作者所有,翻译仅用于学习。

    基于Promise编写异步代码时,通常会使用多个then组成链式调用,每一个then都会有一个回调函数。因此,在Promise链中,会有很多回调函数,每个回调函数都有一个独立的变量作用域。那么,如何在这些回调函数之间共享变量呢?这篇博客将探讨这个问题。

    问题

    connection变量在A处定义,在BC处都需要使用。但是,由于A、B、C处于各自独立的作用域,connection变量将不能在BC处直接使用。

    db.open()
    .then(connection => // A
    {
    return connection.select(
    {
    name: 'Fundebug'
    });
    })
    .then(result =>
    {
    connection.query(); // B
    })
    .catch(error =>
    {
    // ...
    })
    .finally(() =>
    {
    connection.close(); // C
    });

    方法1:使用高阶作用域变量

    在更高阶的作用域定义connection变量,在D处赋值,这样在BC处直接使用了。

    let connection; // A
    db.open()
    .then(conn =>
    {
    connection = conn; // D
    return connection.select(
    {
    name: 'Fundebug'
    });
    })
    .then(result =>
    {
    connection.query(); // B
    })
    .catch(error =>
    {
    // ...
    })
    .finally(() =>
    {
    connection.close(); // C
    });

    问题:如果需要共享的变量过多(这是很常见的情况),则需要在高阶作用域中定义很多变量,这样非常麻烦,代码也比较冗余。

    方法2:嵌套作用域

    将需要使用connection变量的Promise链内嵌到对应then回调函数中,这样在BC处直接使用了。

    db.open()
    .then(connection => // A
    {
    return connection.select(
    {
    name: 'Fundebug'
    })
    .then(result =>
    {
    connection.query(); // B
    })
    .catch(error =>
    {
    // ...
    })
    .finally(() =>
    {
    connection.close(); // C
    });
    });

    问题:之所以使用Promise,就是为了避免回调地域,将多层嵌套的回调函数转化为链式的then调用;如果为了共享变量采用嵌套写法,则要Promise有何用?

    方法3:return多个值

    intermediate变量在A处定义并赋值,而在B处需要使用;但是,由于AB处于不同的作用域,B出并不能直接使用intermediate变量:

    return asyncFunc1()
    .then(result1 =>
    {
    const intermediate = ··· ; // A
    return asyncFunc2();
    })
    .then(result2 =>
    {
    console.log(intermediate); // B
    });

    A处使用Promise.all返回多个值,就可以将intermediate变量的值传递到B处:

    return asyncFunc1()
    .then(result1 =>
    {
    const intermediate = ···;
    return Promise.all([asyncFunc2(), intermediate]); // A
    })
    .then(([result2, intermediate]) =>
    {
    console.log(intermediate); // B
    });

    问题: 使用Promise.all用于传递共享变量,看似巧妙,但是有点大材小用,并不合理;不能将变量传递到.catch()finally()中;当共享变量过多,或者需要跨过数个.then(),需要return的值会很多。

    方法4: 使用Async/Await

    Async/Await是写异步代码的新方式,可以替代Promise,它使得异步代码看起来像同步代码,可以将多个异步操作写在同一个作用域中,这样就不存在传递共享变量的问题了!!!

    方法1中的示例可以改写为:

    try
    {
    var connection = await db.open(); // A
    const result = await connection.select(
    {
    name: 'Fundebug'
    });
    connection.query(); // B
    }
    catch (error)
    {
    // ...
    }
    finally
    {
    connection.close(); // C
    }

    方法3中的示例可以改写为:

    try
    {
    result1 = await asyncFunc1();
    const intermediate = ··· ;
    result2 = await asyncFunc2();
    console.log(intermediate);
    }
    catch (error)
    {
    // ...
    }

    毋庸赘言,Async/Await直接将问题消灭了,无疑是更好的方式!

    参考


    关于Fundebug :

    Fundebug专注于JavaScript、微信小程序、微信小游戏、支付宝小程序、React Native、Node.js和Java实时BUG监控。 自从2016年双十一正式上线,Fundebug累计处理了7亿+错误事件,得到了Google、360、金山软件、百姓网等众多知名用户的认可。欢迎免费试用!

     

  • 相关阅读:
    混用Int与IntPtr导致GetProcAddress始终返回null
    Net中获取程序集路径
    Sql server 2014 同一数据库换名还原,导致同名库一直处于还原状态
    微耕N3000注入
    Xaramin IOS 开发常见问题
    Vs2017 xaramin mac build agent部署后记
    Git 笔记
    spring AOP
    JAVA 反射原理
    Hyperledger Fabric:fabric private data技术【官方文档翻译】
  • 原文地址:https://www.cnblogs.com/fundebug/p/7474893.html
Copyright © 2011-2022 走看看