译者按: 使用Promise写过异步代码的话,会发如今Promise链中共享变量是一个很是头疼的问题,这也是Async/Await赛过Promise的一点,咱们在Async/Await替代Promise的6个理由有提过,这篇博客将有更详细的介绍。javascript
为了保证可读性,本文采用意译而非直译,而且对源代码进行了大量修改。另外,本文版权归原做者全部,翻译仅用于学习。html
基于Promise编写异步代码时,一般会使用多个then组成链式调用,每个then都会有一个回调函数。所以,在Promise链中,会有不少回调函数,每一个回调函数都有一个独立的变量做用域。那么,如何在这些回调函数之间共享变量呢?这篇博客将探讨这个问题。java
connection变量在A处定义,在B和C处都须要使用。可是,因为A、B、C处于各自独立的做用域,connection变量将不能在B和C处直接使用。node
db.open() .then(connection => // A { return connection.select( { name: 'Fundebug' }); }) .then(result => { connection.query(); // B }) .catch(error => { // ... }) .finally(() => { connection.close(); // C });
在更高阶的做用域定义connection变量,在D处赋值,这样在B和C处直接使用了。es6
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 });
问题:若是须要共享的变量过多(这是很常见的状况),则须要在高阶做用域中定义不少变量,这样很是麻烦,代码也比较冗余。promise
将须要使用connection变量的Promise链内嵌到对应then回调函数中,这样在B和C处直接使用了。异步
db.open() .then(connection => // A { return connection.select( { name: 'Fundebug' }) .then(result => { connection.query(); // B }) .catch(error => { // ... }) .finally(() => { connection.close(); // C }); });
问题:之因此使用Promise,就是为了不回调地域,将多层嵌套的回调函数转化为链式的then调用;若是为了共享变量采用嵌套写法,则要Promise有何用?async
intermediate变量在A处定义并赋值,而在B处须要使用;可是,因为A与B处于不一样的做用域,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的值会不少。
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/201...