1

I have tried using Promise.race(), but in this case too if one of the Promise is resolved the other Promises keep on running.

Is there a way to stop other processes from running once one of them wins.

I do not want other processes to keep running and using system resources.

I am open to use other ways instead of promises to implement this.

In practice PromiseA is waiting for PromiseZ (I am using the following code to mock similar behaviour)

Since I know now after running PromiseA that PromiseB is not required, I want to stop PromiseB

Is there any better way to do this?

var promiseList = [];

var flag = false;


function PromiseA() {
    return new Promise(function(resolve, reject) {
        setTimeout(function() {
            console.log(flag)
            flag = true;
            resolve();
        }, 2000);
    });
}


function PromiseB() {
    return new Promise(function(resolve, reject) {
        setTimeout(function() {
            if (flag === true) {
                console.log('checking')
                console.log('flag is:' + flag)
                resolve();
            } else {
                reject();
            }
        }, 7000);
    });
}



promiseList.push(PromiseA());
promiseList.push(PromiseB());




Promise.all(promiseList);




Abdullah Khilji
  • 370
  • 2
  • 8
  • The [`Promise` API](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) does not support cancellation. – jsejcksn May 29 '22 at 08:01
  • @jsejcksn I am open to explore other ways instead of Promise – Abdullah Khilji May 29 '22 at 08:02
  • @AbdullahKhilji If you share your actual code, then a potential alternative suggestion can be made. Currently, we can only guess what you are trying to accomplish. – jsejcksn May 29 '22 at 08:04
  • Does this answer your question? [Promise - is it possible to force cancel a promise](https://stackoverflow.com/questions/30233302/promise-is-it-possible-to-force-cancel-a-promise) – snnsnn May 29 '22 at 08:05
  • @jsejcksn have add some code snippet for some context – Abdullah Khilji May 29 '22 at 08:13
  • @AbdullahKhilji Thanks for clarifying. I've provided [an answer](https://stackoverflow.com/a/72422205/438273) based on the code you've shown. – jsejcksn May 29 '22 at 08:50

2 Answers2

2

According to ECMAScript specification you can not cancel an ongoing promise.

However you can abort a fetch request using AbortController which be used not only for fetch but also for other asynchronous tasks.

Is there a way to stop other processes from running once one of them wins.

You can chain the expensive computation in a way to run once the earlier promise is resolved.

If you want to cut down on server resources you can run each promise one by one or chain them.

const promiseA = () => new Promise((resolve, reject) => reject('Some value'));
const promiseB = () => new Promise((resolve, reject) => resolve('Other value'));

Promise.resolve(10)
  .then(promiseA).catch(promiseB)
  .then(val => console.log(val))
  .catch(err => console.log(err));
snnsnn
  • 10,486
  • 4
  • 39
  • 44
1

Following up on my comment:

The Promise API does not support cancellation. Therefore, you'll have to design a cancellation mechanism into your own API.

Here's a slight modification to the code in your question which does exactly that using the AbortController API:

let flag = false;

function PromiseA(abortSignal) {
  return new Promise(function(resolve, reject) {
    setTimeout(function() {
      if (abortSignal.aborted) {
        reject();
        return;
      }
      console.log(flag)
      flag = true;
      resolve();
    }, 2000);
  });
}

function PromiseB(abortSignal) {
  return new Promise(function(resolve, reject) {
    setTimeout(function() {
      if (abortSignal.aborted) {
        reject();
        return;
      }
      if (flag === true) {
        console.log('checking')
        console.log('flag is:' + flag)
        resolve();
      } else {
        reject();
      }
    }, 7000);
  });
}

async function main () {
  const ac = new AbortController();

  const promiseList = [
    PromiseA(ac.signal),
    PromiseB(ac.signal),
  ].map(p => p.then(() => ac.abort()));

  await Promise.any(promiseList);
  console.log('done');
}

main();
jsejcksn
  • 27,667
  • 4
  • 38
  • 62
  • Thanks this helps, but will this instantly abort the PromiseB when PromiseA updates the signal? If not can we make that happen in any possible way? – Abdullah Khilji May 29 '22 at 10:22
  • Also why AbortController is a better way instead of declaring global variables? – Abdullah Khilji May 29 '22 at 10:32
  • @AbdullahKhilji (1) "_will this instantly abort the PromiseB when PromiseA updates the signal?_": No, it will only abort once the conditional statement is reached. (2) "_If not can we make that happen in any possible way?_": No. (3) "_why AbortController is a better way instead of declaring global variables?_": _Better_ is subjective. `AbortController` was designed for exactly this kind of scenario. You are free to use globals if you don't care about code reusability across module boundaries. – jsejcksn May 30 '22 at 04:37