1

I am new to Javascript and nodejs. While trying to understand how promises and callbacks work, i tried calling a function in a 'for' loop as shown below. What i was trying to achieve is to print 'i' value every 2 seconds using promises. However, the program waits for 2 seconds and prints i value 3 times and exits.

for(let i = 0; i < 3 ; i++){
    func(callback,i);
}

async function func(callback,i){
   await callback(i);
}
function callback(i){
    return new Promise((res,rej) =>{
        setTimeout(()=>{
            console.log('i = ',i)
            res();
        }, 2000);

    })
}

Can anybody please help me understand why this is happening?

3
  • 2
    Your func is pretty needless. You could just call callback(i) directly, with the same result. Commented Jan 18, 2020 at 20:44
  • It’s because async keyword transform func returns to Promise, and you should use await when func calls (if you want to wait while this Promise will be resolved). Commented Jan 18, 2020 at 23:18
  • ALL async functions return a promise. If you want the for loop to pause, you have to await the promise that func() returns. Commented Jan 19, 2020 at 2:17

5 Answers 5

3

You are pretty close. The missing information is async functions (your func()) implicitly returns an AsyncFunction object which implicitly returns a Promise itself too (doc).

Your code using immediately invoked function expression would be

(async () => {
    for(let i = 0; i < 3 ; i++){
        await func(callback,i);
    }
})()

async function func(callback,i){
   await callback(i);
}
function callback(i){
    return new Promise((res,rej) =>{
        setTimeout(()=>{
            console.log('i = ',i)
            res();
        }, 2000);
    })
}

Please note now in most of the browsers is natively available the construct for await..of (doc). You can try experimenting this one too.

Sign up to request clarification or add additional context in comments.

Comments

3

You can just wrap your loop with async immediately executed function and add await within it (as was already suggested here):

(async () => {
  for(let i = 0; i < 3 ; i++){
    await callback(i);
  }
})();

function callback(i){
  return new Promise((res,rej) =>{
    setTimeout(()=>{
      console.log('i = ',i)
      res();
    }, 2000);
  })
}

Here is my original answer before Bergi's edit:

(async () => {
  for(let i = 0; i < 3 ; i++){
    await func(callback,i);
  }
})()

async function func(callback,i){
  await callback(i);
}

function callback(i){
  return new Promise((res,rej) =>{
    setTimeout(()=>{
      console.log('i = ',i)
      res();
    }, 2000);
  })
}

Comments

-1

You need to wait for async function to complete

for(let i = 0; i < 3 ; i++){
    await func(callback,i);
}

But since you can't use await keyword in the global scope, you will need to wrap your for loop in an async function, and than call it

async function myTest(){
    for(let i = 0; i < 3 ; i++){
        await func(callback,i);
    }
}
myTest()

Comments

-1

Here are some functions which help you understand how promises work with Arrays, where we make common mistakes.

function promiseFunction(v) {
    return new Promise((resolve) => {
        setTimeout(() => resolve(v), 1000);
    });
}
function f1() {
    [1, 2, 3, 4]. forEach(async(i) => {
        const v = await promiseFunction(i);
        console.log(`-f1 v- ${v}<br/>`);
    });
    console.log('all done<br/>');
}
async function f2() {
    await Promise.all([1, 2, 3, 4].map(async(i) => {
        const v = await promiseFunction(i);
        console.log(`-f2 v- ${v}<br/>`);
    }));
    console.log('all done<br/>');
}
async function f3() {
    await [1, 2, 3, 4].reduce((p, i) => {
        return p.then(async () => {
            const v = await promiseFunction(i);
            console.log(`-f3 v- ${v}<br/>`);
        });
    }, Promise.resolve());
    console.log('all done<br/>');
}

async function func() {
   console.log('f1');
   await f1();
   console.log('f2');
   await f2();
   console.log('f3');
   await f3();
}

func();

f1() will print all done first and then print 1,2,3,4 at once after a second.
f2() will print 1,2,3,4 at once after a second then print all done.
f3() will print 1,2,3,4 in every second, and then print all done.

1 Comment

Needs to be in an async function context though....which is not what is showing in OP code. Try running it yourself
-2

You async function func also returns a promise so you need the await keyword before its call.

for(let i = 0; i < 3 ; i++){
    await func(callback,i);
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.