首页 > 解决方案 > 循环后执行的循环中的 Promise 回调

问题描述

我习惯于等待,但 eslint 讨厌它循环。Eslint 也不喜欢在循环中定义函数。因此,我在 Vuex 脚本中得到了以下代码段:

  // wait until the file is synchronized
  let waitTime = 100;
  let fileExists = false;
  const checkSync = (res, i) => {
    console.log(res.status);
    if (res.status === 200) {
      fileExists = true;
      console.log('Status 200, setting fileExists=true');
    } else if (res.status === 404) {
      Vue.$log.debug(`Image not ready for download ${res.status}`);
      setTimeout(() => { waitTime = (i < 4) ? 200 : 1000; }, waitTime);
      console.log(`waitTime = ${waitTime}`);
    }
  };
  for (let i = 0; !fileExists && i < 5; i += 1) {
    console.log(`fileExists = ${fileExists}`);
    axios.head(`${response.data.data.url}`).then(resp => checkSync(resp, i));
  }

但是日志显示循环内的第一个日志语句是一个接一个地执行的,而带有 promise/resolve 的第二个语句是在循环完成时执行的。我可以重写代码来等待并忽略 eslint,但我希望我最终能更深入地了解古老的承诺。

fileExists = false
fileExists = false
fileExists = false
fileExists = false
fileExists = false
items.js:175 200
items.js:178 Status 200, setting fileExists=true
items.js:175 200
items.js:178 Status 200, setting fileExists=true
items.js:175 200
items.js:178 Status 200, setting fileExists=true
items.js:175 200
items.js:178 Status 200, setting fileExists=true
items.js:175 200
items.js:178 Status 200, setting fileExists=true

更新

我通常这样做的方式。Eslint 抱怨,但代码是由用户在上传新图片时触发的,所以我不需要关心效率。

  // wait until the file is synchronized on backend to www node
  let waitTime = 100;
  for (let i = 0; i < 5; i += 1) {
    // eslint-disable-next-line no-await-in-loop
    const head = await axios.head(response.data.data.url);
    if (head.status === 200) {
      return response.data;
    } else if (head.status === 404) {
      Vue.$log.debug(`Image not ready for download ${head.status}`);
      // eslint-disable-next-line no-loop-func
      setTimeout(() => { waitTime = (i < 4) ? 200 : 1000; }, waitTime);
      console.log(`waitTime = ${waitTime}`);
    }
  }

标签: javascript

解决方案


// This function does promised function from array one-by-one
const reducePromise = (items = [], callback) => (
  items.reduce(async (promisedAcc, curr) => {
    const acc = await promisedAcc;
    const currentResult = await callback(curr);
    return acc.concat(currentResult);
  }, Promise.resolve())
)

// This Function resolves promise after time that passed by param
const wait = (time = 0) => new Promise((resolve) => setTimeout(() => resolve(), time))

let fileExists = false;

reducePromise([...Array(5).keys()], async (i) => {
  await axios.head(`${response.data.data.url}`)
  .then(res => {
    fileExists = true;
    console.log('Status 200, setting fileExists=true');
  })
  .catch(({ response: res }) => {
    Vue.$log.debug(`Image not ready for download ${res.status}`);
    const waitTime = (i < 4) ? 200 : 1000;
    return wait(waitTime)
  })
})

https://developers.google.com/web/fundamentals/primers/async-functions#example_outputting_fetches_in_order


推荐阅读