0

I'm racing three promises. One of them should never resolve unless a specific condition is met, but it still resolves itself.

myFunction() is meant to wait for a blockchain transaction to get confirmed. It can have statuses: confirmed, unconfirmed and failed. My issue is that statusCheck gets resolved and returns nothing when receiving "unconfirmed".

I wish to make this function strictly:

  • resolve on "confirmed"
  • reject on "failed"
  • ignore "unconfirmed" and wait until successListener resolves

How should I approach this?

public async myFunction() {

    const successListener = rxjs.firstValueFrom(transactionConfirmationObservable)
        .then(async result => {
            return result;
            // Listens for transaction status change to "confirmed"
        });

    const failureListener = rxjs.firstValueFrom(transactionFailureObservable)
        .then(async result => {
            throw new Error(result);
            // Listens for transaction status change to "failed"
        });

    const statusCheck = axios(currentTransacionStatusRequest)
        .then(async result => {
            if (result == "confirmed") return result;
            if (result == "failed") throw new Error(result);
            // Checks status in case it became confirmed/failed before the listeners opened.
            //
            // Expected beviour: if result is "unconfirmed" - do nothing.
            // Actual behaviour: resolves even with result "unconfirmed".
        });

    return Promise.race([successListener, failureListener, statusCheck]);
  • 2
    What are those observables and how to they relate to your (axios) request? – trincot Jan 23 '23 at 14:24
  • 4
    Btw, do not use `async` functions as `.then()` callbacks. – Bergi Jan 23 '23 at 14:37
  • You could return a promise that never resolves, but that doesn't sound like a good idea. Rather, listen to the observables only once the ajax request didn't confirm the transaction? – Bergi Jan 23 '23 at 14:40
  • You need to control the statusCheck resolution/rejection yourself. `const statusCheck = new Promise(async (res, rej) => { const result = await axios(...); if (result === 'confirmed') return res(result); if (result === 'failed') return rej(result); })` That way statusCheck won't resolve or reject. Presumably you'll do that in a loop or something? – Trevor Dixon Jan 23 '23 at 14:58
  • 1
    @TrevorDixon No, [don't do that](https://stackoverflow.com/q/23803743/1048572?What-is-the-promise-construction-antipattern-and-how-to-avoid-it)! And [certainly not with `async`/`await`](https://stackoverflow.com/q/43036229/1048572)! – Bergi Jan 23 '23 at 15:01
  • @Bergi He wants to make a Promise that doesn't resolve that's dependent on a promise that does, so he needs to take control of the resolve and reject callbacks, so I think what I said is the best way to do precisely what he's asking to do. To be clear though, I think your comment above my first is even better advice though. Some kind of refactoring would make this better. – Trevor Dixon Jan 23 '23 at 19:56
  • A Promise that never resolves is sometimes OK. Not great here though. statusCheck should be an Observable, not a Promise. – Trevor Dixon Jan 23 '23 at 19:57

1 Answers1

-1

Fixed it by creating new promises so I could explicitly resolve and reject them. Now I can prevent statusCheck from resolving itself when it finishes execution.

public async myFunction() {

    const successListener = new Promise(async (resolve, reject) => {
        const result = await rxjs.firstValueFrom(transactionConfirmationObservable);
        resolve(result);
    });

    const failureListener = new Promise(async (resolve, reject) => {
        const result = await rxjs.firstValueFrom(transactionFailureObservable);
        reject(new Error(result));
    });

    const statusCheck = new Promise(async (resolve, reject) => {
        const result = await axios(currentTransacionStatusRequest);
        if (result == "confirmed") resolve(result);
        if (result == "failed") reject(new Error(result));
    });

    return Promise.race([successListener, failureListener, statusCheck]);
}
  • [Avoid the `Promise` constructor antipattern](https://stackoverflow.com/q/23803743/1048572?What-is-the-promise-construction-antipattern-and-how-to-avoid-it) and [never pass an `async` function as the executor](https://stackoverflow.com/q/43036229/1048572)! – Bergi Jan 24 '23 at 10:53