javascript - 如何在异步函数中处理多个等待
问题描述
我有多个 API 调用要进行,它们通过 API 获取,通过 API 将数据写入 DB,通过另一个 API 将输出发送到前端。
我已经用 await 编写了异步函数,如下所示 -
前 2 个应该一个接一个地运行,但第三个可以独立运行,无需等待前 2 个 fetch 语句完成。
let getToken= await fetch(url_for_getToken);
let getTokenData = await getToken.json();
let writeToDB = await fetch(url_for_writeToDB);
let writeToDBData = await writeToDB.json();
let frontEnd = await fetch(url_for_frontEnd);
let frontEndData = await frontEnd.json();
处理此类多个 fetch 语句的最佳方法是什么?
解决方案
如果您使用 Promise “创建者”(= 返回 Promise 的函数)而不是原始 Promise,它会更容易。首先,定义:
const fetchJson = (url, opts) => () => fetch(url, opts).then(r => r.json())
它返回这样一个“创造者”。现在,这里有两个用于串行和并行链接的实用程序,它们同时接受原始承诺和“创建者”:
const call = f => typeof f === 'function' ? f() : f;
const parallel = (...fns) => Promise.all(fns.map(call));
async function series(...fns) {
let res = [];
for (let f of fns)
res.push(await call(f));
return res;
}
然后,主要代码可以这样写:
let [[getTokenData, writeToDBData], frontEndData] = await parallel(
series(
fetchJson(url_for_getToken),
fetchJson(url_for_writeToDB),
),
fetchJson(url_for_frontEnd),
)
如果您不喜欢专用的“创建者”包装器,您可以fetchJson
正常定义
const fetchJson = (url, opts) => fetch(url, opts).then(r => r.json())
series
并在或被parallel
调用的地方使用内联延续:
let [[getTokenData, writeToDBData], frontEndData] = await parallel(
series(
() => fetchJson('getToken'),
() => fetchJson('writeToDB'),
),
() => fetchJson('frontEnd'), // continuation not necessary, but looks nicer
)
为了进一步推动这个想法,我们也可以制造series
和parallel
回报“创造者”,而不是承诺。这样,我们可以构建串行和并行承诺的任意嵌套“电路”并按顺序获得结果。完整的工作示例:
const call = f => typeof f === 'function' ? f() : f;
const parallel = (...fns) => () => Promise.all(fns.map(call));
const series = (...fns) => async () => {
let res = [];
for (let f of fns)
res.push(await call(f));
return res;
};
//
const request = (x, time) => () => new Promise(resolve => {
console.log('start', x);
setTimeout(() => {
console.log('end', x)
resolve(x)
}, time)
});
async function main() {
let chain = series(
parallel(
series(
request('A1', 500),
request('A2', 200),
),
series(
request('B1', 900),
request('B2', 400),
request('B3', 400),
),
),
parallel(
request('C1', 800),
series(
request('C2', 100),
request('C3', 100),
)
),
);
let results = await chain();
console.log(JSON.stringify(results))
}
main()
.as-console-wrapper { max-height: 100% !important; top: 0; }
推荐阅读
- c - 为什么逻辑或导致此“-Wint-conversion”警告?
- python - 如何按自定义重叠时段对熊猫数据框进行分组?
- asp.net-core - 从 IdentityServer 5 中的 IdP EndSessionEndpoint 检索“sid”声明?
- go - 无法将 terraform variables.tf 文件读入 may go 程序
- javascript - 有没有办法将 css 应用于元素的一部分?
- javascript - 我不断收到错误:require is not defined
- google-chrome-theme - 有没有办法为操作系统中的明暗模式指定不同的 Chrome 主题颜色?
- c++ - 为什么 Visual Studio 只返回整数?
- python - 按长期月平均年查找变异性月度数据
- ruby - RSpec shared_examples 有条件地检查块是否存在