我如何在地图函数中异步和增量地获取数据

How can i asynchronously and incrementally fetch data inside a map function

我正在尝试从数组中逐步获取剧集,因此用户体验如下所示:

用户点击一个按钮,显示一个加载指示器,加载在 div 中获取的第一集,但一直在第一集下方显示加载指示器,一直这样做直到地图结束为止剧集已提取,加载指示器不再显示。

但显然,这似乎没有按计划工作,我怀疑 async-await 在地图中没有按预期工作。

我想知道像 rxjs 这样的东西在这个用例中是否有帮助(我不知道它是如何工作的,但我知道它用于数据流式传输的情况)

  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState('');
  const [data, setData] = useState([]);

  const handleClick = async () => {
    try {
      season.episodes.map(async (episode) => {
        setIsLoading(true);
        const links = await publicQueryClientApi(
          `${process.env.NEXT_PUBLIC_SERVER_URL}/download/${episode.slug}`
        );
        setIsLoading(false);
        setData((prev) => [...prev, { episode, links }]);
        setError('');
      });
    } catch (error) {
      setIsLoading(false);
      setData([]);
      setError(error.message);
    }
  };

async 函数总是 returns a Promise.

您可以尝试这样的操作:

const promises = season.episodes.map(async episode => {
  const links = await fetchLinks()
  // do other stuff
  return links
})

const links = await Promise.all(promises)

另一件事是,只有当您想要数组的副本但已修改时才使用 map(使用传递给 map 的函数,该函数将在每个数组项上执行) .据我所知,map 函数中的 return 值未保存在任何地方。

为什么不只使用递归函数,它会获取每一集,并在有“未获取”的剧集时再次调用自身来获取另一个? (不要忘记每次都将剧集标记为“已提取”,否则会无限循环)。

array.mapawait 它的回调,如果它是异步的。所以

的结果
[...].map(async x => {})

是一组未决的承诺。如果你想一个一个地添加你的episode,你应该使用一个

try {
  for (let episode of season.episodes) {
    setIsLoading(true);
    const links = await publicQueryClientApi(
      `${process.env.NEXT_PUBLIC_SERVER_URL}/download/${episode.slug}`
    );
    setIsLoading(false);
    setData((prev) => [...prev, { episode, links }]);
    setError('');
  }
} catch (e) {
  ...
}

由于您的代码已经在 async 函数中,因此无需任何进一步修改即可运行。

另一种可能性是使用 Promise.all(),一旦数组中的所有 promise 都被解析并且return它们的结果在数组中

,这将解析
try {
  setIsLoading(true);
  let allLinks = await Promise.all(season.episodes.map(e => {
    return publicQueryClientApi(...);
  });
  setIsLoading(false);

  setData(season.episodes.map((e,i) => ({
     episode: e,
     links: alllinks[i]
  }));
  setError('');
} catch (e) {
  ...
}