-2

`I've made calls to six built-in APIs within a for loop, where each API call depends on the result of the previous one. I've attempted to execute these API calls synchronously; however, due to varying response times, achieving true synchronicity has proven challenging.

for (let i = 0; i < 2; i++) {
    let promise1 = new Promise((resolve, reject) => {
        resolve("Promise 1 ");
    });

    let promise2 = new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve("Promise 2");
        }, 1000);
    });

    let promise3 = new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve("Promise 3");
        }, 2000);
    });

    let promiseExecution = async () => {
        for (let promise of [promise2, promise3, promise1]) {
            // console.log('promise',promise)
            try {
                const message = promise;
                console.log(message);
            } catch (error) {
                console.log(error.message);
            }
        }
    };
    promiseExecution();
}

Expected: promise 2 promise 3 promise 1 promise 2 promise 3 promise 1

2
  • 1
    You create all three promises at the same time. Are you sure that is your real case?
    – trincot
    Commented Sep 11, 2023 at 11:21
  • @Keith my previous comments were unfounded, my bad and now deleted. More appropriately I should have pointed out that the async keyword before the promiseExecution function is meaningless because the function executes synchronously.
    – traktor
    Commented Sep 11, 2023 at 12:17

2 Answers 2

2

You're just missing two await operators. You need one to get the message, and one to await promiseExecution(). For the latter you need to wrap the whole script in an async function.

However, you create the three promise objects at the same time, so that does not really reflect your actual case where "each API call depends on the result of the previous one". If they are dependent, then you would only create the second promise after the first one resolves, ...etc.

So I would turn these into three functions that when called, create their respective promise:

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

// Three functions for creation promises
const task1 = () => Promise.resolve("Promise 1");
const task2 = () => delay(1000).then(() => "Promise 2");
const task3 = () => delay(2000).then(() => "Promise 3");

async function chainOfThree() {
    for (const task of [task2, task3, task1]) {
        const message = await task(); // <---- create promise only now, and await
        console.log(message);
    }
}

async function main() { 
    for (let i = 0; i < 2; i++) {
        await chainOfThree(); // <---- wait for all three to resolve
    }
}

main().catch(error => console.log("error", error.message));

Note that I moved the error handling to the outermost layer, as it is not helpful to catch an error in a middle layer, which then rejects the promise returned by the async function, only to leave that rejection unhandled.

1

If your wanting to wait for an array of promises, you can use Promise.all()

Below is an example, I've also used another function run, to also make your loop async, as you also want to await promiseExecution();

Note: Although this answer seems to give the same result as trincots, there is a difference. trincot has serialized your promises, but here they are in parallel. IOW: trincot's answer takes about 6 seconds to complete, were this takes about 4 seconds. Now you did say -> API calls synchronously; so technically trincots answer is maybe what your after here, but unless promise2 rely's on promise1, and promise 3 relies on promise2 then using Promise.all would make more sense.

async function run() {
    for (let i = 0; i < 2; i++) {
        let promise1 = new Promise((resolve, reject) => {
            resolve("Promise 1 ");
        });

        let promise2 = new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve("Promise 2");
            }, 1000);
        });

        let promise3 = new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve("Promise 3");
            }, 2000);
        });

        let promiseExecution = async () => {
            for (let promise of await Promise.all([promise2, promise3, promise1])) {
                // console.log('promise',promise)
                try {
                    const message = promise;
                    console.log(message);
                } catch (error) {
                    console.log(error.message);
                }
            }
        };
        await promiseExecution();
    }
}

run();

Without using async / await you would still use Promise.all, but there is some code refactoring to do, the trick here is to make the loop work just place inside another function and at the end of the Promise.all increment i, and then check if < 2 and if it is just call loop again. IOW: this will have the same effect then as for loop but keep the promise chain intact. Also remember to always to return the promise when doing this.

function run() {
    let i = 0;
    function loop() {

        let promise1 = new Promise((resolve, reject) => {
            resolve("Promise 1 ");
        });

        let promise2 = new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve("Promise 2");
            }, 1000);
        });

        let promise3 = new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve("Promise 3");
            }, 2000);
        });

        let promiseExecution = () => {
            return Promise.all([promise2, promise3, promise1]).then(messages => {
                for (const message of messages) {
                    console.log(message);
                }
            })
        };

        return promiseExecution().then(() => {
            i++;
            if (i < 2) return loop();
        });
    }
    
    return loop();
}

run();

2
  • In Thingsboard, an older version of ECMAScript (ES) is used, which does not support the async-await functionality. As a result, I am seeking an alternative method to handle asynchronous operations without relying on async-await. Commented Sep 12, 2023 at 11:42
  • @user22536823 Updated to include a none async / await verison.
    – Keith
    Commented Sep 12, 2023 at 12:11

Not the answer you're looking for? Browse other questions tagged or ask your own question.