【问题标题】:wait for one fetch to finish before starting the next等待一次提取完成,然后再开始下一次提取
【发布时间】:2022-03-17 16:29:50
【问题描述】:

我有一个要发送到谷歌云的数据列表。我当前的代码如下所示:

const teams = ['LFC', 'MUFC', 'CFC'];

teams.forEach(team => {
    fetch({
      url: URL,
      method: 'PUT',
      body: team
    });
})

这适用于一个team,但如果发送多个文件并且文件更大,则会超时。我正在发送图像而不是字符串。为了解决这个问题,我需要将POST的数据逐个文件,并等待前一个POST完成后再发送下一个。任何人都可以建议最好的方法吗?

值得注意的是,我无法控制 已上传。

【问题讨论】:

  • 如果你可以访问npm,你可以安装bluebird并使用Promise.reduce; Promise.reduce 将在它们解析时一个接一个地执行一组 Promise,并允许您将先前的结果“减少”为一个最终结果。

标签: javascript ajax ecmascript-6 fetch-api


【解决方案1】:

使用reduce 代替forEach,使用.then()

下面会将最后一个fetch的promise存储在accreduce的累加器参数)中,并在then监听器中附加新的fetch,以确保之前的@ 987654329@完结:

const teams = ['LFC', 'MUFC', 'CFC'];

teams.reduce((acc, team) => {
  return acc.then(() => {
    return fetch({
      url: URL,
      method: 'PUT',
      body: team
    });
  })
}, Promise.resolve())
  .then(() => console.log("Everything's finished"))
  .catch(err => console.error("Something failed:", err))

//Simulate fetch:
const fetch = team => new Promise(rs => setTimeout(() => {rs();console.log(team)}, 1000))

const teams = ['LFC', 'MUFC', 'CFC'];

teams.reduce((acc, team) => {
  return acc.then(() => {
    return fetch({
      url: URL,
      method: 'PUT',
      body: team
    });
  })
}, Promise.resolve())
  .then(() => console.log("Everything's finished"))
  .catch(err => console.error("Something failed:", err))

你甚至可以为它写一个通用的辅助函数:

const teams = ['LFC', 'MUFC', 'CFC'];

const promiseSeries = cb => teams.reduce((acc, elem) => acc.then(() => cb(elem)), Promise.resolve())

promiseSeries((team) => {
  return fetch({
    url: URL,
    method: 'PUT',
    body: team
  })
})
  .then(() => console.log("Everything's finished"))
  .catch(err => console.error("Something failed:", err))

//Simulate fetch:
const fetch = team => new Promise(rs => setTimeout(() => {rs();console.log(team)}, 1000))

const teams = ['LFC', 'MUFC', 'CFC'];

const promiseSeries = cb => teams.reduce((acc, elem) => acc.then(() => cb(elem)), Promise.resolve())

promiseSeries((team) => {
  return fetch({
    url: URL,
    method: 'PUT',
    body: team
  })
})
  .then(() => console.log("Everything's finished"))
  .catch(err => console.error("Something failed:", err))

或者,更好的是,如果可以(它是 ES2017),请使用 async/await(它更具可读性):

const teams = ['LFC', 'MUFC', 'CFC'];

async function upload(teams){
  for(const team of teams){
    await fetch({
      url: URL,
      method: 'PUT',
      body: team
    });
  }
}

upload(teams)
  .then(() => console.log("Everything's finished"))
  .catch(err => console.error("Something failed:", err))

//Simulate fetch:
const fetch = team => new Promise(rs => setTimeout(() => {rs();console.log(team)}, 1000))

const teams = ['LFC', 'MUFC', 'CFC'];

async function upload(teams) {
  for (const team of teams) {
    await fetch({
      url: URL,
      method: 'PUT',
      body: team
    });
  }
}

upload(teams)
  .then(() => console.log("Everything's finished"))
  .catch(err => console.error("Something failed:", err))

【讨论】:

  • 我要提一下,这围绕着 Promises,对于那些不熟悉的人。
【解决方案2】:

您可以将 async/await 与 for...of 循环一起使用。每次调用都会“保持”循环,直到它完成,然后循环将继续下一次调用:

const teams = ['LFC', 'MUFC', 'CFC'];

async function send(teams) {
  for (const team of teams) {
    await fetch({
      url: URL,
      method: 'PUT',
      body: team
    });
  }
}

【讨论】:

  • 这是一个不错的解决方案,而且比上一个更整洁,但我现在才看到它并给出了绿色的勾号!不过谢谢!
  • @Peter 如果您认为应该接受更好的答案,您可以随时更改已接受的答案。
  • @WaiHaLee 我知道,但接受的答案添加了相同的内容,不确定是在此答案之前还是之后
【解决方案3】:

你可以使用async/await,如下:

const teams = ['LFC', 'MUFC', 'CFC'];

teams.forEach(async (team) => {
    await fetch({
      url: URL,
      method: 'PUT',
      body: team
    });
})

【讨论】:

  • async/await 是否在 forEach 回调中工作?我认为它在任何 Array 高阶函数中都不起作用... EDIT 刚刚测试过,正如我所怀疑的那样,它不起作用。如果您制作一个简单的基于 Promise 的延迟函数,该函数包含 setTimeout 和未排序的时间数组(如 100、500、250),那么带有 await 的 for...of... 会按数组顺序正确运行它们,而forEach 按时间顺序异步运行它们。
猜你喜欢
  • 2020-04-14
  • 2020-11-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-31
  • 2016-08-17
  • 1970-01-01
  • 2022-10-04
相关资源
最近更新 更多