摘要:那么,如何在這些回調函數之間共享變量呢這篇博客將探討這個問題。
譯者按: 使用Promise寫過異步代碼的話,會發現在Promise鏈中共享變量是一個非常頭疼的問題,這也是Async/Await勝過Promise的一點,我們在Async/Await替代Promise的6個理由有提過,這篇博客將有更詳細的介紹。
原文: Passing data between Promise callbacks
譯者: Fundebug
為了保證可讀性,本文采用意譯而非直譯,并且對源代碼進行了大量修改。另外,本文版權歸原作者所有,翻譯僅用于學習。
基于Promise編寫異步代碼時,通常會使用多個then組成鏈式調用,每一個then都會有一個回調函數。因此,在Promise鏈中,會有很多回調函數,每個回調函數都有一個獨立的變量作用域。那么,如何在這些回調函數之間共享變量呢?這篇博客將探討這個問題。
問題connection變量在A處定義,在B和C處都需要使用。但是,由于A、B、C處于各自獨立的作用域,connection變量將不能在B和C處直接使用。
db.open() .then(connection => // A { return connection.select( { name: "Fundebug" }); }) .then(result => { connection.query(); // B }) .catch(error => { // ... }) .finally(() => { connection.close(); // C });方法1:使用高階作用域變量
在更高階的作用域定義connection變量,在D處賦值,這樣在B和C處直接使用了。
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回調函數中,這樣在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有何用?
方法3:return多個值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的值會很多。
方法4: 使用Async/AwaitAsync/Await是寫異步代碼的新方式,可以替代Promise,它使得異步代碼看起來像同步代碼,可以將多個異步操作寫在同一個作用域中,這樣就不存在傳遞共享變量的問題了?。。?/p>
方法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...
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/88557.html
摘要:如果不希望定義多余的外層變量,則需要在鏈中的每一個函數中都返回變量,這樣做顯然更加糟糕。 譯者按: 通過真實的代碼示例感受Async/Await的力量。 原文: Async/await - A thorough example 譯者: Fundebug 為了保證可讀性,本文采用意譯而非直譯。另外,本文版權歸原作者所有,翻譯僅用于學習。 既然Node.js 8已經LTS了,我想大...
摘要:當前函數執行完成后,當前函數的執行上下文出棧,并等待垃圾回收。作用域與作用域鏈到來有全局作用域函數作用域和塊級作用域新增。 引言 Javascript是前端面試的重點,本文重點梳理下 Javascript 中的常考知識點,然后就一些容易出現的題目進行解析。限于文章的篇幅,無法將知識點講解的面面俱到,本文只羅列了一些重難點,如果想要了解更多內容歡迎點擊我的博客。 一、變量類型 1.JS ...
摘要:當前函數執行完成后,當前函數的執行上下文出棧,并等待垃圾回收。作用域與作用域鏈到來有全局作用域函數作用域和塊級作用域新增。 引言 Javascript是前端面試的重點,本文重點梳理下 Javascript 中的??贾R點,然后就一些容易出現的題目進行解析。限于文章的篇幅,無法將知識點講解的面面俱到,本文只羅列了一些重難點,如果想要了解更多內容歡迎點擊我的博客。 一、變量類型 1.JS ...
摘要:三是控制反轉控制權在其他人的代碼上,假如異步函數是別人提供的庫,我們把回調函數傳進去,我們并不能知道異步函數在調用回調函數之外做了什么事情。錯誤捕捉相比回調函數的錯誤無法在外部捕捉的問題,能夠為一連串的異步調用提供錯誤處理。 前言 《JS異步編程之 callback》一文我們了解了JS 是基于單線程事件循環的概念構建的,回調函數不會立即執行,由事件輪詢去檢測事件是否執行完畢,當執行完有...
摘要:技術上來說這個機制被稱為動態分配或代理。定義類一個類是一個正式的抽象集,它規定了對象的初始狀態和行為。技術上來說一個類表示構造函數原型的組合。因此構造函數創建對象并自動設置新創建實例的原型。第二次調用時,相同的上下文再次被壓入棧并恢復。 原文:JavaScript. The Core: 2nd Edition作者:Dmitry Soshnikov 文章其他語言版本:俄語 這篇文章是 ...
閱讀 1607·2021-11-04 16:11
閱讀 3320·2021-09-09 11:33
閱讀 1568·2019-08-30 15:54
閱讀 624·2019-08-30 15:44
閱讀 3183·2019-08-30 15:43
閱讀 2565·2019-08-30 13:06
閱讀 1705·2019-08-29 17:00
閱讀 906·2019-08-29 15:33