譯者按: 使用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...