【问题标题】:How to properly map over array of url and get data into state?如何正确映射 url 数组并使数据进入状态?
【发布时间】:2021-01-15 22:06:56
【问题描述】:

在这个代码块中,我正在映射一组 Spotify 网址,获取那里的数据,并尝试将它们推入状态。截至目前,此代码返回一组承诺,并且不等待实际数据。这对我来说没有意义,因为我正在等待来自 axios 调用的数据。

const fetchSpotifyData = async () => {
    const allTracks = data.map(async (d) => {
      let track = {
        album: "",
        image: "",
        artist: "",
        trackName: "",
        externalUrl: "",
      };
      const incomingTrack = await axios.get(
        `https://api.spotify.com/v1/tracks/${d.uri}`,
        {
          headers: {
            Authorization: `Bearer ${spotifyToken}`,
          },
        }
      );
      console.log(incomingTrack) // the data is here and is correct
      track.album = incomingTrack.data.album.name;
      track.image = incomingTrack.data.album.images[0].url;
      track.artist = incomingTrack.data.artists[0].name;
      track.trackName = incomingTrack.data.name;
      track.externalUrl = incomingTrack.data.external_urls.spotify;
      console.log(track) // this shows the correct track data
      return track;
    });
        console.log(allTracks)// Array [ Promise {
  //  "_U": 0,
   // "_V": 0,
  //  "_W": null,
  //  "_X": null,
 // },
 // ]

  return allTracks;
  };

【问题讨论】:

  • 如果您将async 回调传递给任何循环数组方法,例如forEachmap 等。那么你必须 Promise.all 结果数组。方法本身不会在循环之间await。或者,您可以使用 for...of 循环单独处理每个 Promise。

标签: javascript reactjs react-native axios


【解决方案1】:

这里的问题似乎是函数的性质,您正在等待一系列承诺而不是承诺本身。

另一种和大多数建议的解决方案是简单地从地图返回承诺。这样你就会有一系列的承诺。

从那里,您可以使用Promise.all 来解决这些承诺。 Promise.all 接收一个 promises 数组,或者你也可以使用Promise.allSettled

阅读更多关于Promise.all

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all


const fetchSpotifyData = async () => {
    const allTracks = data.map((d) => {

      return axios.get(
        `https://api.spotify.com/v1/tracks/${d.uri}`,
        {
          headers: {
            Authorization: `Bearer ${spotifyToken}`,
          },
        }
      );

    });
  return allTracks;
  };
let track = {
  album: "",
  image: "",
  artist: "",
  trackName: "",
  externalUrl: "",
};

Promise.all(fetchSpotifyData()).then((data) => {
  // do you operations
})
      

【讨论】:

    【解决方案2】:

    使用您的代码的简化版本,您会看到您需要的是Promise.all

    根据文档:

    Promise.all() 方法将 可迭代 的 Promise 作为输入,并返回单个 Promise,该 Promise解析为结果数组 的输入承诺。

    在您的情况下,可迭代对象是一个数组。由于它会返回一个带有结果的承诺,因此您也需要 await 它。

    下面我创建了一个 sn-p,以便您更好地了解正在发生的事情。请注意,我用自己的承诺将 Spotify axios API 调用排除在外,但输入和输出应该足够相似:

    const spotifyStubPromise = (songId) => new Promise((resolve, reject) => resolve([
      {album: "Programming is Great"},
      {album: "But Code Is Hard"},
    ][songId]));
    
    data = [{id: 0}, {id: 1}];
    
    const fetchSpotifyData = async () => {
      const allTracks = data.map(async (song) => {
        let track = {
          album: "",
        };
        const incomingTrack = await spotifyStubPromise(song.id);
        console.log("Incoming track -> ", incomingTrack) // the data is here and is correct
        track.album = incomingTrack.album;
        console.log("Processed track -> ", track) // this shows the correct track data
        return track;
      });
      console.log("all tracks (array of Promises) -> ", allTracks);
      
      
      
      const allTracksSync = await Promise.all(allTracks); // waits for all the promises to finish
      console.log("all tracks (array of data) -> ", allTracksSync);
      return allTracks;
    };
    
    fetchSpotifyData();

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-04-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-22
      • 2021-07-17
      • 2014-03-04
      相关资源
      最近更新 更多