【问题标题】:JS/React - How should I use a fetch call inside of a for loop?JS/React - 我应该如何在 for 循环中使用 fetch 调用?
【发布时间】:2021-04-29 01:01:31
【问题描述】:

除了最简单的形式之外,我对异步函数还有些陌生,所以我希望这里有人可以帮助我。

一些信息:

getCollection() 返回一个如下所示的对象数组。

{
  "id": 1,
  "userId": 3,
  "gameId": 3498,
  "review": "Testing review for game 1"
},

getGameById() 接收一个整数(游戏的 id)并从外部 API 返回该游戏对象。

gameArray 应该充满游戏对象,其外部 API 中的 ID 与 getCollection 提供的对象数组中的 ID 匹配。

const [games, setGames] = useState([])

const getGames = () => {
        getCollection().then(userGames => {
            let gameArray = []
            for (const eachObj of userGames) {
                if (eachObj.userId === currentUserId) {
                    getGameById(eachObj.gameId).then(game => {
                        gameArray.push(game)
                        })
                }
            }
            Promise.all(gameArray).then(() => {
                console.log(gameArray) //logs empty array, but shouldn't be empty
                setGames(gameArray)
            })
        })
    }

我以前从未使用过 Promise.all,这只是我认为可以解决我遇到的这个问题的一种方法。

【问题讨论】:

    标签: javascript for-loop promise fetch


    【解决方案1】:

    Promise.all 接受一系列承诺。

    首先你必须构建一个promise数组。然后你必须用这个数组调用Promise.all 来检索所有的游戏:

    function getGames() {
        getCollection().then(userGames => {
            const gamePromises = userGames
                   .filter(userGame => userGame.userId == currenUserId)
                   .map(userGame => getGameById(userGame.gameId));
    
            Promise.all(gamePromises).then(games=> {
                console.log(games);
                setGames(games)
            });
        })
    }
    

    这是另一个使用async function 的解决方案,它可能更具可读性

    async function getGames() {
      const userGames = await getCollection();
      const currentUserGames = userGames.filter(({userId}) => userId == currentUserId);
      const games = await Promise.all(userGames.map(({gameId}) => getGameById(gameId));
      setGames(games);
    }
    

    【讨论】:

    • 好的,效果很好。谢谢你。我试图理解 Promise.all 是如何用于我搜索的现有问题的,但是你在这里写它的方式对我来说实际上是有意义的。我不知道为什么,但是我在这个网站上看到的很多代码(即使是我熟悉的语言)对我来说看起来很陌生,我很难理解它的意义,以便我自己复制,无需复制/粘贴。我会赞成你的回答,但目前我的声誉和蚂蚁一样大。
    • 你必须明白,当你做getGameById(eachObj.gameId).then(game => { gameArray.push(game) })then里面写的代码不会立即执行,会在api返回响应后执行。因此,当您在代码中到达 Promise.all 时,gameArray 为空,因为没有一个 gameArray.push 被执行。
    【解决方案2】:

    您传递给Promise.all 的数组需要包含promise,但是您正在推送游戏对象——而且您是异步执行的,所以当您将它传递给Promise.all 时,该数组仍然是空的。

    const getGames = () => {
        getCollection().then(userGames => {
            let gamePromises = []
            for (const eachObj of userGames) {
                if (eachObj.userId === currentUserId) {
                    gamePromises.push(getGameById(eachObj.gameId))
    //              ^^^^^^^^^^^^^^^^^^                           ^
                }
            }
            return Promise.all(gamePromises)
    //      ^^^^^^ chaining
        }).then(gameArray => {
    //          ^^^^^^^^^
            console.log(gameArray)
            setGames(gameArray)
        })
    }
    

    为了简化:

    async function getGames() {
        const userGames = await getCollection()
        const gamePromises = userGames
            .filter(eachObj => eachObj.userId === currentUserId)
            .map(eachObj => getGameById(eachObj.gameId))
        const gameArray = await Promise.all(gamePromises)
        console.log(gameArray)
        setGames(gameArray)
    }
    

    【讨论】:

    • 这与发布的第一个答案一样有效。你们基本上给出了相同的解决方案,只是写的有点不同。谢谢。
    猜你喜欢
    • 1970-01-01
    • 2012-02-15
    • 2018-07-03
    • 1970-01-01
    • 2020-11-28
    • 2020-06-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多