[英]How to make run nested asynchronous methods synchronously?
如何在Promise中包裝此例程,以便我只在獲取所有數據時解析?
var accounts = [];
getAccounts(userId, accs => {
accs.forEach(acc => {
getAccountTx(acc.id, tx => {
accounts.push({
'id': acc.id,
'tx': tx
});
});
})
});
編輯:如果我這樣做會有任何問題嗎?
function getAccountsAllAtOnce() {
var accounts = [];
var required = 0;
var done = 0;
getAccounts(userId, accs => {
required = accs.length;
accs.forEach(acc => {
getAccountTx(acc.id, tx => {
accounts.push({
'id': acc.id,
'tx': tx
});
done = done + 1;
});
})
});
while(done < required) {
// wait
}
return accounts;
}
讓我們將這個例程放入一個單獨的函數中,以便以后再使用它更容易。 這個函數應該返回一個promise,它將通過一組帳戶解析(我也會盡可能地修改你的代碼):
function getAccountsWithTx(userId) {
return new Promise((resolve, reject) => {
var accounts = [];
getAccounts(userId, accs => {
accs.forEach(acc => {
getAccountTx(acc.id, tx => {
accounts.push({
'id': acc.id,
'tx': tx
});
// resolve after we fetched all accounts
if (accs.length === accounts.length) {
resolve(accounts);
}
});
});
});
});
}
唯一的區別就是在獲取所有帳戶后返回承諾並解決。 但是,當你有很多嵌套回調時,回調會使你的代碼庫具有這種“回調地獄”風格,並且很難對其進行推理。 您可以使用良好的規則來解決它,但您可以大大簡化它,切換到從所有異步函數返回的promise。 例如,您的func將如下所示:
function getAccountsWithTx(userId) {
getAccounts(userId)
.then(accs => {
const transformTx = acc => getAccountTx(acc.id)
.then(tx => ({ tx, id: acc.id }));
return Promise.all(accs.map(transformTx));
});
}
它們都是完全等價的,並且有很多庫可以“宣傳”你當前的回調式函數(例如, bluebird甚至本機Node util.promisify )。 此外,使用新的異步/等待語法,它變得更加容易,因為它允許在同步流中思考:
async function getAccountsWithTx(userId) {
const accs = await getUserAccounts(userId);
const transformTx = async (acc) => {
const tx = getAccountTx(acc.id);
return { tx, id: acc.id };
};
return Promise.all(accs.map(transformTx));
}
如您所見,我們消除了任何嵌套! 它使得代碼的推理變得更加容易,因為您可以讀取實際執行的代碼。 但是,所有這三個選項都是等價的,因此由您決定,在您的項目和環境中最有意義的是什么。
我將每一步都拆分成自己的函數,並從每個函數返回一個promise或promise數組。 例如,getAccounts變為:
function getAccountsAndReturnPromise(userId) {
return new Promise((resolve, reject) => {
getAccounts(userId, accounts => {
return resolve(accounts);
});
});
};
並且getAccountTx解析為{id,tx}對象的數組:
function getAccountTransactionsAndReturnPromise(accountId) {
return new Promise((resolve, reject) => {
getAccountTx(account.id, (transactions) => {
var accountWithTransactions = {
id: account.id,
transactions
};
return resolve(accountWithTransactions);
});
});
};
然后,您可以使用Promise.all()
和map()
以您希望的格式將最后一步解析為值數組:
function getDataForUser(userId) {
return getAccountsAndReturnPromise(userId)
.then(accounts=>{
var accountTransactionPromises = accounts.map(account =>
getAccountTransactionsAndReturnPromise(account.id)
);
return Promise.all(accountTransactionPromises);
})
.then(allAccountsWithTransactions => {
return allAccountsWithTransactions.map(account =>{
return {
id: account.id,
tx: tx
}
});
});
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.