javascript - 难以理解这个 Promise + async await 示例以在 JavaScript 中检索多个用户信息
问题描述
在 javascript 的 promise 和 async await 上关注本教程(https://javascript.info/fetch ),但无法理解它提供的练习。
问题是关于从 Github 检索多个用户信息。每个用户一个获取请求。请求不应该相互等待。以便数据尽快到达。
它提供的解决方案是
async function getUsers(names) {
let jobs = [];
for(let name of names) {
let job = fetch(`https://api.github.com/users/${name}`).then(
successResponse => {
if (successResponse.status != 200) {
return null;
} else {
return successResponse.json();
}
},
failResponse => {
return null;
}
);
jobs.push(job);
}
let results = await Promise.all(jobs);
return results;
}
我的第一个问题是,我们可以await
用于获取吗?即以下片段是否等同于他提供的解决方案?
async function getUsers2(names) {
let jobs = [];
for(let name of names) {
let response
try {
response = await fetch(`https://api.github.com/users/${name}`);
} catch(e) {
response = null
}
const job = response && response.json()
jobs.push(job);
}
let results = await Promise.all(jobs);
return results;
}
此外,教程说
.then 调用直接附加到 fetch,因此当我们有响应时,它不会等待其他 fetch,而是立即开始读取 .json()。
如果我们使用 await Promise.all(names.map(name => fetch(...))),并在结果上调用 .json(),那么它将等待所有 fetch 响应。通过将 .json() 直接添加到每个 fetch,我们确保各个 fetch 开始以 JSON 格式读取数据,而无需相互等待。
他的意思是如果我们这样写解决方案
async function getUser(name) {
const response = await fetch(`https://api.github.com/users/${name}`)
return response.ok ? await response.json : null
}
async function getUsers(names) {
return await Promise.all(names.map(name => getUser(name)))
}
我们将无法达到这样的效果,即我们不希望请求不应该互相等待?
解决方案
我的第一个问题是,我们可以使用 await 进行获取吗?即以下片段是否等同于他提供的解决方案?
不。当在异步函数的直接主体中时,只要有await
,该函数将完全暂停,直到以下 Promise 解决。所以,循环
for(let name of names) {
let response
try {
response = await fetch(`https://api.github.com/users/${name}`);
} catch(e) {
response = null
}
在继续初始化下一个请求之前,需要串行等待每个响应的标头被接收。
他的意思是如果我们这样写解决方案
首先需要调整语法:.json
是一个方法,所以需要调用:
async function getUser(name) {
const response = await fetch(`https://api.github.com/users/${name}`)
return response.ok ? await response.json() : null
// ^^
}
但这完全没问题。函数中唯一await
的getUsers
就是等待整体 Promise.all
解决;.map
数组对调用的pinggetUser
是同步执行的,因此所有请求都会立即发送出去,因此没有一个网络请求需要等待其他任何一个请求完成才能工作。
作者所指的问题是调用调用Promise.all
数组fetch
,而不是.json()
调用数组:
// Bad, do not use:
const getUsers = async (names) => {
const responses = await Promise.all(names.map(
name => fetch(`https://api.github.com/users/${name}`)
));
return Promise.all(responses.map(
response => response.ok ? response.json() : null
));
}
上面的问题是脚本必须等待每个请求的所有响应标头都被接收,然后才能开始解析它们中的任何一个的响应主体。
另一个并行解决方案:
const getUsers = names => Promise.all(names.map(
async (name) => {
const res = await fetch(`https://api.github.com/users/${name}`);
return res.ok ? res.json() : null;
}
));
推荐阅读
- java - 异步获取数据,然后用 RxJava 串行处理数据
- ansible - 使用 ansible 顺序赋值
- amazon-web-services - 尝试放置数据时出现 AWS lambda documentClient.put 错误
- vue.js - 增加 Vue.js 中组件数量的性能成本
- php - Docusign Api - 使用复合模板时文档不会更改
- c# - 什么是“真实”?
- python - 将字典从模块返回到主模块
- html - Rvest - 使用 html 数据框而不是网页 - 并提取格式化标签
- python - 命令提示符中“main.py”和“python main.py”的区别
- arrays - 功能。2个二维数组,第二个全为0,应用条件后,将第一个二维数组的整行复制到第二个二维数组