我正在尝试写这样的东西,但无法解决内心的承诺。
const traceSamplesRequests = transactionTypes.map(async (transactionType) => {
// This part should be synchronous since we need transactionNames
const transactionNames = await api.getTransactionNames();
return transactionNames.map((transactionName) => api.getTraceSamples());
});
我想用 Promise 编写 lambda 函数。所有的都不是命令式循环。
所以,
.map()
不是承诺感知的。它调用回调,并尽职尽责地收集回调的返回值,然后前进到循环的下一次迭代。由于您的回调是 async
,其中包含 await
,因此该返回值是一个未解决的承诺。所以,你从.map()
得到的是一系列承诺。
因此,如果不使用某些东西来等待承诺,就无法使用
.map()
或任何数组迭代方法。
听起来您已经知道这一点,但是使用您拥有的代码,您将插入两个
Promise.all()
语句:
const traceSamplesRequests = await Promise.all(transactionTypes.map(async (transactionType) => {
// This part should be synchronous since we need transactionNames
const transactionNames = await api.getTransactionNames();
return Promise.all(transactionNames.map((transactionName) => api.getTraceSamples()));
}));
这将为您提供一个值数组(并且父函数必须是
async
)。这将并行运行循环中的所有异步操作(所有操作同时进行)。
您的其他选择是使用
for
或 while
循环,它将暂停每个 await
的循环迭代,并按顺序运行异步操作(循环的第二次迭代在第一个迭代完成之前不会运行)。
或者,您可以编写某种辅助函数,它是
.map()
的承诺感知版本。不过,您可能只是在辅助函数中使用 for
或 .map()
与 Promise.all()
。
const traceSamplesRequests = await Promise.all(
transactionTypes.map(async (transactionType) => {
const transactionNames = await api.getTransactionNames({ transactionType });
return await Promise.all(transactionNames.map((transactionName) => api.getTraceSamples({ transactionType })));
})
);
function hasNestedPromises(value: unknown): boolean {
if (value instanceof Promise) {
return true
} else if (Array.isArray(value)) {
return value.some(hasNestedPromises)
} else if (value && typeof value === 'object') {
return Object.values(value).some(hasNestedPromises)
}
return false
}
export function reolsveNestedPromises(value: unknown): unknown | Promise<unknown> {
//not very efficient but in order to avoid process object like Set, Date, ecc we need to perform this check every time
if (!hasNestedPromises(value)) {
return value
}
if (value instanceof Promise) {
return value.then(reolsveNestedPromises)
} else if (Array.isArray(value)) {
return Promise.all(value.map(reolsveNestedPromises))
} else if (value && typeof value === 'object') {
return Promise.all(Object.values(value).map(reolsveNestedPromises)).then((values) => {
return Object.fromEntries(Object.keys(value).map((key, index) => [key, values[index]]))
})
}
return value
}