文档章节

如何在Promise链中共享变量?

Fundebug
 Fundebug
发布于 2017/09/04 18:16
字数 988
阅读 8
收藏 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
粉丝 6
博文 126
码字总数 193991
作品 0
厦门
私信 提问
致莫名其妙火起来的面试之补充篇

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

酸楚与甘甜
07/18
0
0
【译】JavaScript:核心 - 第二版 - 网络埋伏纪事

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

awufan
07/12
0
0
使用 Promises 编写更好的 JavaScript 代码

你可能已经无意中听说过 Promises 是多么的代表未来。所有酷孩子们都使用它们,但你不知道为什么它们如此特别。难道你不能使用回调么?有什么了不起的?在本文中,我们将看看promises是什么以...

oschina
2014/04/19
5.4K
16
JavaScript Promise 学习记录(一)

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

kkdev163
2017/11/27
0
0
ES6 系列之我们来聊聊 Promise

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

冴羽
10/16
0
0

没有更多内容

加载失败,请刷新页面

加载更多

十万个为什么之为什么大家都说dubbo

Dubbo是什么? 使用背景 dubbo为什么这么流行, 为什么大家都这么喜欢用dubbo; 通过了解分布式开发了解到, 为适应访问量暴增,业务拆分后, 子应用部署在多台服务器上,而多台服务器通过可以通过d...

尾生
31分钟前
2
0
Docker搭建代码质量检测平台-SonarQube(中文版)

Sonar是一个用于代码质量管理的开源平台,用于管理源代码的质量,可以从七个维度检测代码质量。通过插件形式,可以支持包括java,C#,C/C++,PL/SQL,Cobol,JavaScrip,Groovy等等二十几种编程语言...

Jacktanger
37分钟前
2
0
Windows / Linux / MacOS 设置代理上网的方法汇总

本文汇总了 Windows / Linux / MacOS 设置代理上网的各种方法,总结如下: 1、设置系统代理(Windows、Linux、MacOS) 2、设置代理插件(Chrome、Chromium、Firefox、Opera、QQ等浏览器) 3、...

sunboy2050
昨天
4
0
自定义 Maven 的 repositories

有时,应用中需要一些比较新的依赖,而这些依赖并没有正式发布,还是处于milestone或者是snapshot阶段,并不能从中央仓库或者镜像站上下载到。此时,就需要 自定义Maven的<repositories>。 ...

waylau
昨天
3
0
徒手写一个es6代码库

mkdir democd demonpm initnpm install -g babelnpm install -g babel-clinpm install --save-dev babel-preset-es2015-node5 在项目目录创建两个文件夹 functional-playground ......

lilugirl
昨天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部