如何在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;
}
答案 0 :(得分:2)
让我们把这个例程放到一个单独的函数中,以便以后重用它。这个函数应该返回一个promise,它将通过一组帐户解析(我也会尽可能地修改你的代码):
basename($_SERVER['PHP_SELF'])
唯一的区别就是在获取所有帐户后返回承诺并解决。但是,当你有很多嵌套回调时,回调会使你的代码库具有这种“回调地狱”风格,并且很难对其进行推理。您可以使用良好的规则来解决它,但您可以大大简化它,切换到从所有异步函数返回的promise。例如,您的func将如下所示:
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);
}
});
});
});
});
}
它们都是完全等效的,并且有很多库可以“宣传”你当前的回调式函数(例如,bluebird甚至本机节点util.promisify)。此外,使用新的async/await syntax它变得更加容易,因为它允许在同步流中思考:
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));
});
}
如您所见,我们消除了任何嵌套!它使得代码的推理变得更加容易,因为您可以读取实际执行的代码。但是,所有这三个选项都是等价的,因此它取决于您,在您的项目和环境中最有意义的。
答案 1 :(得分:1)
我将每一步拆分成自己的函数,并从每个函数返回一个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
}
});
});
}