我想为Wikimedia API中提取的locations数组中的每个对象添加一个description属性,但是当我在循环中记录它的值时,它会在那里,但是在循环之外,它会被删除。
我找到了使用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 answer解释了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
的解决方案:
我正在通过.map
在locations
数组上创建一个Promises数组。
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);
});