nick
nick

Reputation: 3229

Javascript cancel async for loop

I found this code in a project:

const fn = async () => {
    let x = 0;
    for(let i = 0; i < 50; i++){
        const res = await api.call(i);
        if(res.someProp) x++;
    }

    return x;
}

I want to be able to stop it mid way, so that if I call it again, it will start from scratch and discard the previous call results. To avoid making two sets of requests at the same time.

Upvotes: 1

Views: 1651

Answers (2)

Dmitriy Mozgovoy
Dmitriy Mozgovoy

Reputation: 1597

You can use any technique of using an external flag variable to break the loop.

As a workaround you can try to use a custom Promise class (Live demo):

import CPromise from "c-promise2";

const delay = ms => new Promise(resolve => setTimeout(resolve, ms));

async function api(i) {
  console.log(`Async API call [${i}]`);
  await delay(100);
  return {};
}

const fn = () =>
  CPromise.from(function* () {
    let x = 0;
    for (let i = 0; i < 50; i++) {
      const res = yield api.call(i);
      if (res.someProp) x++;
    }

    return x;
  });

const cancelablePromise = fn().then(
  () => console.log("Done"),
  (err) => console.log(`Fail: ${err}`) // Fail: CanceledError: canceled 
);

setTimeout(() => {
  cancelablePromise.cancel(); // abort the async sequence (loop) after 3500ms
}, 3500);

Upvotes: 0

Bergi
Bergi

Reputation: 664246

This should do:

let token;
const fn = async () => {
    const my = token = Symbol();
    let x = 0;
    for(let i = 0; i < 50 && my == token; i++){
        const res = await api.call(i);
        if(res.someProp) x++;
    }

    return x;
}

While there still can be some overlap between the calls, any previous loops will break their iteration as soon as the next fn() call is started.

Upvotes: 1

Related Questions