文档章节

如何在Promise链中共享变量?

Fundebug
 Fundebug
发布于 2017/09/04 18:16
字数 988
阅读 7
收藏 0

译者按: 使用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以及本文地址:

https://blog.fundebug.com/2017/09/04/promise-share-variable/

© 著作权归作者所有

共有 人打赏支持
Fundebug
粉丝 4
博文 83
码字总数 129168
作品 0
厦门
致莫名其妙火起来的面试之补充篇

先是致谢 第一次发面试经历莫名其妙有了很多人看,记一次凉凉的小米面试内心还是十分的激(peng)动(zhang),不行不行,做技术的还是不能膨胀的。非常感谢给我举例JSON进行深拷贝有部分缺陷...

酸楚与甘甜
07/18
0
0
JavaScript Promise 学习记录(一)

JavaScript Promise 学习记录(一) 本文首先介绍了promise的三种状态及生成不同状态promise方法,然后介绍了promise的回调处理方法then,分析了不同情况下then函数返回的promise状态。最后通过...

kkdev163
2017/11/27
0
0
玩转异步 JS :async/await 简明教程(附视频下载)

课程介绍 在软件开发领域,简洁的代码 => 容易阅读的代码 => 容易维护的代码,而 ES2017 中的 async/await 特性能让我们编写出相比回调地狱和 Promise 链式调用更直观、更容易理解的代码,a...

王仕军
09/14
0
0
ES6 系列之我们来聊聊 Promise

前言 Promise 的基本使用可以看阮一峰老师的 《ECMAScript 6 入门》。 我们来聊点其他的。 回调 说起 Promise,我们一般都会从回调或者回调地狱说起,那么使用回调到底会导致哪些不好的地方呢...

冴羽
昨天
0
0
【译】JavaScript:核心 - 第二版 - 网络埋伏纪事

这是JavaScript:核心概述讲稿的第二版,致力于ECMAScript编程语言及其运行时系统的核心组件。 目标人群:有经验的程序员、专家。 本文的第一版涵盖了JS语言的通用方面,主要讲解了旧式ES3规...

awufan
07/12
0
0

没有更多内容

加载失败,请刷新页面

加载更多

OSChina 周三乱弹 —— 我们无法成为野兽

Osc乱弹歌单(2018)请戳(这里) 【今日歌曲】 @ _刚刚好: 霸王洗发水这波很骚 手机党少年们想听歌,请使劲儿戳(这里) hahahahahahh @嘻酱:居然忘了喝水。 让你喝可乐的话, 你准忘不了...

小小编辑
33分钟前
1
0
vm GC 日志 配置及查看

-XX:+PrintGCDetails 打印 gc 日志 -XX:+PrintTenuringDistribution 监控晋升分布 -XX:+PrintGCTimeStamps 包含时间戳 -XX:+printGCDateStamps 包含时间 -Xloggc:<filename> 可以将数据保存为......

Canaan_
昨天
0
0
学习设计模式——生成器模式

1. 认识生成器模式 1. 定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示 2. 组成: Builder:生成器接口,定义创建一个Product对象所需要的各个组件的操作,...

江左煤郎
昨天
0
0
C语言精要(第二章:基本数据类型)

2.1 C语言基本数据类型 在计算机术语中,把⼆进制数中的某⼀位数又称为⼀个⽐特(bit)。⽐特这个单位对于计算机⽽⾔,在度量上是最⼩的单位。除了⽐特之外,还有字节(byte)这个术语。⼀个...

ryanliue
昨天
0
0
实现下拉菜单多选框效果

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><li>工作意愿地:<%-- <c:forEach items="${list}" var="list"><input type="checkbox" value="${list......

lanjian28
昨天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部