很难理解这个promise+async等待在JavaScript中检索多个用户信息的示例



遵循了本教程(https://javascript.info/fetch)关于javascript的promise和async wait,很难理解它提供的练习。

问题是关于从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,函数就会完全暂停,直到以下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
//                                      ^^
}

但这完全可以。getUsers函数中唯一的await正在等待整个Promise.all的解析;阵列对getUser调用的.mapping是同步执行的,因此所有请求都会同时发出,因此没有一个网络请求需要等待其他任何请求完成才能工作。

作者所指的问题是在fetch调用数组上调用Promise.all,而不是在.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;
}
));

最新更新