1

I am used to await but eslint hates it in a loop. Eslint does not like defining a function in a loop as well. Therefore I ended up with the following snippet in Vuex script:

  // 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));
  }

But the log reveals that the first log statement inside the loop is executed one by one and the second statement with a promise/resolve is executed when the loop is finished. I could rewrite the code to await and ignore eslint, but I hope I finally get deeper knowledge of good old promises.

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

UPDATE

The way I do it usually. Eslint complains but the code is triggered by a users when they upload new picture so I do not need to care about efficiency.

  // 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}`);
    }
  }
7
  • What does the await version look like? Commented Sep 4, 2021 at 14:38
  • "I am used to await..." - Which would require the knowledge how Promises work o.O "eslint hates it in a loop" - Exactly because of the problem you have with your script... Commented Sep 4, 2021 at 14:38
  • 1
    await in a loop is EXACTLY the solution you need in order to process asynchronous requests one after the other and wait for the last before making the next. ESLint doesn't like it because it's very inefficient and almost always unnecessary. Is there some reason you can't run the requests simultaneously, either with Promise.all or with something like what you have above? It's not clear to me exactly what you're trying to do that requires waiting for each request individually. But if you really need that, just ignore ESLint and use await in a loop... Commented Sep 4, 2021 at 14:41
  • @JohnKugelman That won't change much, because checkSync() (despite its name) is neither "sync" nor does it return something the script could await for (setTimeout()) Commented Sep 4, 2021 at 14:41
  • 1
    setTimeout(() => { waitTime = (i < 4) ? 200 : 1000; }, waitTime); doesn't do anything. If the intention is to sleep you need an await. Commented Sep 5, 2021 at 13:19

1 Answer 1

2
// 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

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for the code but it is too complex for such simple request. I would rather to rewrite it to await.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.