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

Fetch doesn't store the values after the array for loop - 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)

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

我正在通过 .mapping locations 数组来创建 Promise 数组。

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);
});

这只是一个时间问题。您的 fetch 调用正在 异步执行 而代码片段最后一行中的 console.log(...) 语句正在 同步执行 .换句话说,对 fetch 发出的请求的响应将在 console.log(...) 之后 return,并且 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 解决此问题。 解释了 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);
    });