Fetch 不会在循环数组之后存储值 - Javascript



我想为从维基媒体API获取的位置数组中的每个对象添加一个描述属性,但是当我在循环中记录其值时,它就在那里,但在循环之外,它被删除了。

我寻找带有async/await函数或Promise.all((的解决方案,但没有成功。

有没有办法正确存储值以便以后访问它?

let locations = [
{
latLng: [33.975561111111,28.555830555556],
name: 'Saint Catherine's Monastery',
searchTerm: 'Saint Catherine's Monastery',
urlSerchTerm: 'Saint%20Catherine's%20Monastery'
},
{
latLng: [29.91667,31.2],
name: 'Bibliotheca Alexandrina',
searchTerm: 'Bibliotheca Alexandrina',
urlSerchTerm: 'Bibliotheca%20Alexandrina'
}
];
async function fetchAsync (site, location) {
// await response of fetch call
let response = await fetch(site);
// only proceed once promise is resolved
let data = await response.json();
// only proceed once second promise is resolved
location.description = data[2][0];
return location.description;
}
// let fetches = [];
for (let i = 0; i < locations.length; i++) {
let site = `https://en.wikipedia.org/w/api.php?action=opensearch&search=${locations[i].urlSerchTerm}&limit=1&namespace=0&format=json&origin=*`;
fetchAsync(site, locations[i])
}
console.log(locations[1].description)

这只是一个时序问题。fetch调用异步执行,而代码段最后一行中的console.log(...)语句同步执行。换句话说,对fetch发出的请求的响应将在console.log(...)之后返回,并且description属性仍将未定义。

您可以通过查看下面的代码来说服自己这一点,其中console.log(...)语句包装在超时中。现在,获取的描述将被记录下来,而不是undefined

let locations = [
{
latLng: [33.975561111111,28.555830555556],
name: 'Saint Catherine's Monastery',
searchTerm: 'Saint Catherine's Monastery',
urlSerchTerm: 'Saint%20Catherine's%20Monastery'
},
{
latLng: [29.91667,31.2],
name: 'Bibliotheca Alexandrina',
searchTerm: 'Bibliotheca Alexandrina',
urlSerchTerm: 'Bibliotheca%20Alexandrina'
}
];
async function fetchAsync (site, location) {
// await response of fetch call
let response = await fetch(site);
// only proceed once promise is resolved
let data = await response.json();
// only proceed once second promise is resolved
location.description = data[2][0];
return location.description;
}
// let fetches = [];
for (let i = 0; i < locations.length; i++) {
let site = `https://en.wikipedia.org/w/api.php?action=opensearch&search=${locations[i].urlSerchTerm}&limit=1&namespace=0&format=json&origin=*`;
fetchAsync(site, locations[i])
}
window.setTimeout(() => {console.log(locations);}, 5000);

您可以按照@JeremyThille的建议使用Promise.all解决此问题。这个SO答案解释了Promise.all的第二次用法,以防这令人困惑。

let locations = [
{
latLng: [33.975561111111,28.555830555556],
name: 'Saint Catherine's Monastery',
searchTerm: 'Saint Catherine's Monastery',
urlSerchTerm: 'Saint%20Catherine's%20Monastery'
},
{
latLng: [29.91667,31.2],
name: 'Bibliotheca Alexandrina',
searchTerm: 'Bibliotheca Alexandrina',
urlSerchTerm: 'Bibliotheca%20Alexandrina'
}
];
const fetchDescription = (location) => fetch(`https://en.wikipedia.org/w/api.php?action=opensearch&search=${location.urlSerchTerm}&limit=1&namespace=0&format=json&origin=*`);
const descriptionRequests = locations.map(fetchDescription);
Promise.all(descriptionRequests)
.then(responses => Promise.all(responses.map(r => r.json())))
.then(descriptions => {
descriptions.forEach((description, index) => { locations[index].description = description[2][0]; });
})
.then(() => {
console.log(locations);
});

这是我对Promise.all的解决方案:

我正在通过.mappinglocations数组来创建承诺数组。

let locations = [
	{
		latLng: [33.975561111111, 28.555830555556],
		name: "Saint Catherine's Monastery",
		searchTerm: "Saint Catherine's Monastery",
		urlSerchTerm: "Saint%20Catherine's%20Monastery"
	},
	{
		latLng: [29.91667, 31.2],
		name: "Bibliotheca Alexandrina",
		searchTerm: "Bibliotheca Alexandrina",
		urlSerchTerm: "Bibliotheca%20Alexandrina"
	}
];
Promise.all(
locations.map( location => new Promise(async (resolve, reject) => {
let site = `https://en.wikipedia.org/w/api.php?action=opensearch&search=${location.urlSerchTerm}&limit=1&namespace=0&format=json&origin=*`,
response = await fetch(site),
data = await response.json();
location.description = data[2][0];
// console.log("Got description = ", location.description)
resolve();
})))
.then(() => {
	console.log("locations[1].description = ", locations[1].description);
});

最新更新