-1

I have a list of asynchronous functions. I expected when the very first function resolve (or reject), I can stop others.

For examples:

function wait(ms){
    return new Promise(function(resolve){
        setTimeout(function(){
            console.log('waited ', ms);
            resolve();
        }, ms);
    })
}

promise1 = wait(2000);
promise2 = wait(5000);

listPromise = [promise1, promise2];

Promise.race(listPromise).then(function(){
    console.log("Very first promise has resolved!");
})

The actual result is:

> waited  2000
> Very first promise has resolved!
> waited  5000

The expecting result is:

> waited  2000
> Very first promise has resolved!
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
Khanh Le
  • 404
  • 4
  • 18
  • 1
    When the first promise resolves, do you want to *cancel* the other promises's execution and possibly perform cleanup, or do you simply don't want them to call the callback method, but their execution continues, although you don't care about their return value? Please see [this answer](https://stackoverflow.com/questions/30233302/promise-is-it-possible-to-force-cancel-a-promise#30235261) which explains very well how to handle both situations. – Sven Nov 03 '17 at 11:37

2 Answers2

1

You can send a token to your promises to cancel them later.

function wait(ms, token){
    return new Promise(function(resolve){
        var t = setTimeout(function(){
            console.log('waited ', ms);
            resolve();
        }, ms);
        token.cancel = function(){
            clearTimeout(t);
        }
    })
}

var tokens = [{},{},{}];

promise1 = wait(3000,tokens[0]);
promise2 = wait(2000,tokens[1]);
promise3 = wait(5000,tokens[2]);

listPromise = [promise1, promise2,promise3];

var p = Promise.race(listPromise).then(function(){
    console.log("Very first promise has resolved!");
    for(var i = 0; i< listPromise.length; i++)
        tokens[i].cancel();
})

Here is working link : https://jsfiddle.net/Lwymeoz0/

agit
  • 631
  • 5
  • 17
0

Promises are not independent processes that can be cancelled or stopped. If there's a timer running in one of them it will continue doing so unless you stop it yourself.

To solve your particular problem, you would need to keep track of the timeouts that are currently running and, once the first one is resolved, clear all the other timeouts.

Something like this should work:

var timeoutIds = [];

function wait(ms){
    return new Promise(function(resolve){
        var timeoutId = setTimeout(function(){
            console.log('waited ', ms);
            resolve();
        }, ms);
        timeoutIds.push(timeoutId);
    })
}

promise1 = wait(2000);
promise2 = wait(5000);

listPromise = [promise1, promise2];

Promise.race(listPromise).then(function(){
    console.log("Very first promise has resolved!");

    for (var i = 0; i < timeoutIds.length; i++) {
        clearTimeout(timeoutIds[i]);
    }
})
laurent
  • 88,262
  • 77
  • 290
  • 428
  • Thanks for the solution, but I means every async functions, not just particular setTimeout. I've finded the answer in the Svenskunganka's reference. – Khanh Le Nov 03 '17 at 11:52
  • @LittleZero, Yes this solution is for timeouts specifically but for other operations it would be similar. You would keep an instance to, for example, the fetch operation and call "cancel" on it. – laurent Nov 03 '17 at 12:01