skip to Main Content

I am new to JS and trying execute function2 after function1 is finished, below are my function that I am using. But with this implementation I see function2 gets executed before function1 is completely finished.

Function1

function repeatPatternColor(pattern) {
    return new Promise((resolve) => {
        for (let i = 0; i < pattern.length; i++) {
            setTimeout(function () {
                const color = pattern[i];
                const singleCol = document.getElementById(color);

                setTimeout(function () {
                    singleCol.classList.add(`${color}-light`);
                }, (i + 1) * delayMileSec);

                setTimeout(function () {
                    singleCol.classList.remove(`${color}-light`);
                }, (i + 2) * delayMileSec);

                console.log(color);
            }, (i + 1) * delayMileSec);
        }
        resolve();
    });
}

Function2

function generateColor() {
    return new Promise((resolve) => {
        disableDivs();
        const randomNum = Math.floor(Math.random() * 4);
        const id = color[randomNum].id;
        pattern.push(id);
        const singleCol = document.getElementById(id);
        singleCol.classList.add(`${id}-light`);
        setTimeout(function () {
            singleCol.classList.remove(`${id}-light`);
            enableDivs();
        }, 1000);
        console.log("Pattern: " + pattern);
        resolve();
    });
}

Calling Function

async function fnAsync() {
    await repeatPatternColor(pattern);
    await generateColor();
}
let response = fnAsync();

2

Answers


  1. Instead of the model you have adopted currently, I would suggest you have a wait function like this:

    const wait = time => new Promise(res => setTimeout(res, time));
    

    then rewrite your "Function 1" using an asynchronous format, an example below:

    async function repeatPatternColor(pattern) {
        const promises = [];
        for(let i = 0; i < pattern.length; i++)
            promises.push((async () => {
                const color = pattern[i];
                const singleCol = document.getElementById(color);
    
                await wait(delayMileSec);
                singleCol.classList.add(`${color}-light`);
    
                await wait(delayMileSec);
                singleCol.classList.remove(`${color}-light`);
            })());
        await Promise.all(promises);
    }
    

    As you can probably notice, the function is a lot simpler and now truly async! You can try this with your other function too, and as long as you use await wait() and use await for both functions on your fnAsync, it will work the way you want.

    Login or Signup to reply.
  2. The issue is that you are resolving the promise as soon as the loop completes. However, setTimeout does not stop execution of a loop, therefore the resolve will be called before the first timeout even fires.

    Try the following.

    The promise variable will hold the last "classList.remove" promise, which you can await after the loop, or simply return it – as shown in the code

    the fn async function simplifies the code a little, takes a callback and waits for delayMileSec before resolving. You await when you add the "light" class, but don’t await when you remove it. You only await the last "remove" so your next function will be called at the appropriate time

    const pattern = ["red", "green", "blue", "yellow"];
    const delayMileSec = 1000;
    async function repeatPatternColor(pattern) {
        let promise;
        const fn = async (cb) => {
            await new Promise(res => setTimeout(res, delayMileSec));
            cb();
        };
        for(let i = 0; i < pattern.length; i++) {
            const color = pattern[i];
            const singleCol = document.getElementById(color);
            await fn(() => singleCol.classList.add(`${color}-light`));
            promise = fn(() => singleCol.classList.remove(`${color}-light`));
        }
        // await promise;
        // or
        return promise;
    }
    async function fnAsync() {
        await repeatPatternColor(pattern);
        console.log("done");
    }
    fnAsync();
    .x div {
      display: inline-block;
      width:15vw;
      margin: 1em;
      aspect-ratio: 3/1;
    }
    #red {
      background:#990000;
      &.red-light {
        background: #ff0000;
      }
    }
    #green {
      background:#008800;
      &.green-light {
        background: #00ff00;
      }
    }
    #blue {
      background:#000077;
      &.blue-light {
        background: #4444ff;
      }
    }
    #yellow {
      background:#888800;
      &.yellow-light {
        background: #cccc00;
      }
    }
    <div class="x">
    <div id="red"></div>
    <div id="green"></div>
    <div id="blue"></div>
    <div id="yellow"></div>
    </div>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search