6

I want to create somthing like that handle synchronous behavior and asynchronous behavior at the same time. For example I would like to be able something like that :

function timeout(myJson) {
    return new Promise(function (resolve, reject) {
        setTimeout(resolve, myJson.wait, myJson);
    });
}

async function funct() {
    try {
        let PromiseTolaunch = [{ "wait": 10, "nextIndex": 2, "id": 1 }, 
                                { "wait": 500, "nextIndex": -1, "id": 2 }, 
                                { "wait": 5, "nextIndex": -1, "id": 3 }];
        let launchedPromise = [], finishedPromise;

        launchedPromise.push(timeout(PromiseTolaunch[0]));
        launchedPromise[0].id = PromiseTolaunch[0].id;
        launchedPromise.push(timeout(PromiseTolaunch[1]));
        launchedPromise[1].id = PromiseTolaunch[1].id;
        while (launchedPromise.length !== 0) {
            finishedPromise = await Promise.race(launchedPromise);
        [*] console.log(finishedPromise); // Expected output: { "wait": 10, "nextIndex": 2 } 
            //console.log(launchedPromise); // Expected output : [Promise { { wait: 10, nextIndex: 2, id: 1 }, id: 1 }, Promise { <pending>, id: 2 } ]

            //I want to :
            //Remove the promise that just been executed from launchedPromise

            //console.log(launchedPromise); // Expected output : [ Promise { <pending>, id: 2 } ]
            if (finishedPromise.nextIndex !== -1) {
                launchedPromise.push(timeout(PromiseTolaunch[finishedPromise.nextIndex]));
            }
        }
        return Promise.resolve("done")
    } catch (error) {
        return Promise.reject(error);
    }
}

Here i want to remove the promise that returned finishedTest from lunchedPromise What I already tried :

launchedPromise.splice( lunchedTests.indexOf(finishedTest), 1 );
launchedPromise = lunchedTests.filter(prom => prom !== finishedTest);

And it obviously does not work because (finishedTest !== PromiseToLunch[0]) It is not even the same type but I needed to test ^^. I also tried to access to PromiseValue without sucess.

If we conserve only the console.log() that is mark by a [*]. I would like to get the following output :

{ "wait": 10, "nextIndex": 2, "id": 1 }  
{ "wait": 5, "nextIndex": -1, "id": 3 }]
{ "wait": 500, "nextIndex": -1, "id": 2 }
  • 2
    Side nitpick: When you write `lunch` do you mean `launch`? – Patrick Roberts Dec 12 '19 at 16:38
  • 1
    I see now that you only add the first two promises to `lunchedPromise`. I will point out that `nextIndex: 3` will access out of bounds of `PromiseToLunch` since its maximum index is `2` – Patrick Roberts Dec 12 '19 at 16:50
  • 4
    I honestly can't tell what problem you're _actually_ trying to solve, or what _outcome_ you're trying to reach, that you wrote this code for. Can you explain what you're actually trying to achieve, to avoid an [XY Problem](http://xyproblem.info/)? – Mike 'Pomax' Kamermans Dec 12 '19 at 16:52
  • 2
    If you're willing to give each object in `PromiseToLaunch` an `id` property, you could use `launchedPromise.findIndex()` to find the index with `.id === finishedPromise.id` and then splice that index out. – dx_over_dt Dec 12 '19 at 16:56
  • 1
    While we await your explanation of what the code is supposed to do, I want to point out that your code contains some antipatterns like [explicit promise construction](https://stackoverflow.com/questions/23803743/what-is-the-explicit-promise-construction-antipattern-and-how-do-i-avoid-it), and you have demonstrated why this approach is error-prone by forgetting to invoke `resolve()` when the work is complete – Patrick Roberts Dec 12 '19 at 17:01
  • I corrected the errors that pointed out, I didn't know what an antipatterns was before, so I will dig it and also correct it. Thank you btw :) What I want to do is to create a code that can call several API at the same time and when the first response comes we can chain it with one or several API calls until our API call chain has finished. Also, I can't hard code it because I don't know the number of API call I will have to do neither witch API I have to call after. Thank @dx_over_dt, that is exactly what I wanted to do !!! – Adrien CROSIO Dec 12 '19 at 19:11
  • 2
    [Never pass an `async function` as the executor to `new Promise`](https://stackoverflow.com/q/43036229/1048572)! – Bergi Dec 12 '19 at 19:56
  • 2
    No, unfortunately `Promise.race` doesn't allow us finding out which of the promises settled first. You have to keep book of this yourself. See e.g. https://stackoverflow.com/a/38778887/1048572 https://stackoverflow.com/a/50586391/1048572 or https://stackoverflow.com/a/39197252/1048572 for approaches – Bergi Dec 12 '19 at 20:52
  • I tried to remove all antipatterns, can you tell me if i'm right ? – Adrien CROSIO Dec 13 '19 at 09:36

1 Answers1

3

So, the answer to this post is this function:

for (let i = 0; i < LaunchedTests.length; i++) {
    if (LaunchedTests[i].id === finishedTest.scenario + finishedTest.name) {
        return Promise.resolve(LaunchedTests.splice(i, 1));
    }
}
return Promise.reject("not find");

But first you need to initialise an id like that:

let PromiseTolaunch = [{ "wait": 10, "nextIndex": 2, "id": 1 }, 
                       { "wait": 500, "nextIndex": -1, "id": 2 }, 
                       { "wait": 5, "nextIndex": -1, "id": 3 }];
let launchedPromise = [], finishedPromise;
launchedPromise.push(timeout(PromiseTolaunch[0]));
launchedPromise[0].id = PromiseTolaunch[0].id;
launchedPromise.push(timeout(PromiseTolaunch[1]));
launchedPromise[1].id = PromiseTolaunch[1].id;

Your promise will have this form: Promise { <pending>, id: YourId } and you would be able to access to it through passing by the findIndex() function and you just have to splice it.

Thanks to @dx-over-dt and everyone for helping me !