资讯专栏INFORMATION COLUMN

如何在Promise链中共享变量?

_ang / 609人阅读

摘要:那么,如何在这些回调函数之间共享变量呢这篇博客将探讨这个问题。

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

原文: Passing data between Promise callbacks

译者: Fundebug

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

基于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直接将问题消灭了,无疑是更好的方式!

参考

Promises for asynchronous programming

ES proposal: Promise.prototype.finally()

ES proposal: Promise.try()

Async/Await替代Promise的6个理由

版权声明:
转载时请注明作者Fundebug以及本文地址:
https://blog.fundebug.com/201...

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/88557.html

相关文章

  • 一个真实的Async/Await示例

    摘要:如果不希望定义多余的外层变量,则需要在链中的每一个函数中都返回变量,这样做显然更加糟糕。 译者按: 通过真实的代码示例感受Async/Await的力量。 原文: Async/await - A thorough example 译者: Fundebug 为了保证可读性,本文采用意译而非直译。另外,本文版权归原作者所有,翻译仅用于学习。 既然Node.js 8已经LTS了,我想大...

    habren 评论0 收藏0
  • 春招季如何横扫 Javascript 面试核心考点(基础版)?

    摘要:当前函数执行完成后,当前函数的执行上下文出栈,并等待垃圾回收。作用域与作用域链到来有全局作用域函数作用域和块级作用域新增。 引言 Javascript是前端面试的重点,本文重点梳理下 Javascript 中的常考知识点,然后就一些容易出现的题目进行解析。限于文章的篇幅,无法将知识点讲解的面面俱到,本文只罗列了一些重难点,如果想要了解更多内容欢迎点击我的博客。 一、变量类型 1.JS ...

    impig33 评论0 收藏0
  • 春招季如何横扫 Javascript 面试核心考点(基础版)?

    摘要:当前函数执行完成后,当前函数的执行上下文出栈,并等待垃圾回收。作用域与作用域链到来有全局作用域函数作用域和块级作用域新增。 引言 Javascript是前端面试的重点,本文重点梳理下 Javascript 中的常考知识点,然后就一些容易出现的题目进行解析。限于文章的篇幅,无法将知识点讲解的面面俱到,本文只罗列了一些重难点,如果想要了解更多内容欢迎点击我的博客。 一、变量类型 1.JS ...

    jayce 评论0 收藏0
  • JS异步编程之Promise

    摘要:三是控制反转控制权在其他人的代码上,假如异步函数是别人提供的库,我们把回调函数传进去,我们并不能知道异步函数在调用回调函数之外做了什么事情。错误捕捉相比回调函数的错误无法在外部捕捉的问题,能够为一连串的异步调用提供错误处理。 前言 《JS异步编程之 callback》一文我们了解了JS 是基于单线程事件循环的概念构建的,回调函数不会立即执行,由事件轮询去检测事件是否执行完毕,当执行完有...

    Hegel_Gu 评论0 收藏0
  • 【译】JavaScript 核心(第二版)

    摘要:技术上来说这个机制被称为动态分配或代理。定义类一个类是一个正式的抽象集,它规定了对象的初始状态和行为。技术上来说一个类表示构造函数原型的组合。因此构造函数创建对象并自动设置新创建实例的原型。第二次调用时,相同的上下文再次被压入栈并恢复。 原文:JavaScript. The Core: 2nd Edition作者:Dmitry Soshnikov 文章其他语言版本:俄语 这篇文章是 ...

    dingding199389 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<