Fetch不存储数组for循环后的值 - Javascript

问题描述 投票:0回答:2

我想为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)
javascript arrays promise async-await fetch-api
2个回答
1
投票

这只是一个时间问题。你的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);
    });

0
投票

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

我正在通过.maplocations数组上创建一个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);
});
© www.soinside.com 2019 - 2024. All rights reserved.