2

I'm having trouble trying to call a chain of asynchronous functions inside an array. When I call the function individually it works without any problem like in the example below:

function consoleAll(string) {
    return new Promise(function (resolve) {
        console1(string).then(function () {
            console2(string).then(function () {
                resolve();
            });
        });
    });
}
function console1(value) {
    return new Promise((resolve) => {
        console.log(value + "1");
        resolve()
    });
}
function console2(value) {
    return new Promise((resolve) => {
        console.log(value + "2");
        resolve()
    });
}
consoleAll('value-')

In this case the result was the below that is correct:

value-1
value-2

But when it is passed inside a loop it does not make the thread correctly and calls the functions completely out of order

function consoleAll(string) {
    return new Promise(function (resolve) {
        console1(string).then(function () {
            console2(string).then(function () {
                resolve();
            });
        });
    });
}
function console1(value) {
    return new Promise((resolve) => {
        console.log(value + "1");
        resolve()
    });
}
function console2(value) {
    return new Promise((resolve) => {
        console.log(value + "2");
        resolve()
    });
}

//Call
['h1-', 'h2-', 'h3-'].forEach(function (string) {
  consoleAll(string)
});

This time instead of writing the result below:

h1-1
h1-2
h2-1
h2-2
h3-1
h3-2

it outputing this :

h1-1
h2-1
h3-1
h1-2
h2-2
h3-3

It looks like it calls the console1 function for the entire array to then call console2.

Does anyone know the correct way to make this call? PS. I do not care if it is necessary to install some plugins to fix this.

1
  • This code uses the Promise constructor antipattern... Commented Jun 7, 2018 at 14:37

2 Answers 2

5

You have to call logAll again after the previous async call finished:

const values =  ['h1-', 'h2-', 'h3-'];
(function next(i) {
   if(i >= values.length) return;
   consoleAll(values[i]).then(function() {
      next(i + 1);
   });
})(0);

Or if that is to ugly, here is a more modern way:

(async function() {
   for(const string of ["h1-", "h2-", "h3"])
     await consoleAll(string);
})();

And as i noted in the comments, consoleAll is much better written as:

function consoleAll(str) {
  return console1(str).then(function() {
    return console2(str);
  });
}

or:

async function consoleAll(str) {
  await console1(str);
  await console2(str);
}
Sign up to request clarification or add additional context in comments.

2 Comments

Thank you so much, it really saved me. I was already fighting for almost a day with this problem.
@kanzas glad to help :)
1

If you call new Promise(fn), the fn inside is immediately executed. All the .then are pushed to the stack to be executed later, but first the whole .forEach has to pass.

You can see more in this code:

function consoleAll(string) {
    return new Promise(function (resolve) {
        consoleLog(string, 1).then(function () {
            consoleLog(string, 2).then(function () {
                resolve();
            });
        });
        consoleLog(string, 3).then(function () {
            consoleLog(string, 4).then(function () {
                resolve();
            });
        });
    });
}
function consoleLog(value, tag) {
    return new Promise((resolve) => {
        console.log(value + tag);
        resolve()
    });
}

//Call
['h1-', 'h2-', 'h3-'].forEach(function (string) {
  consoleAll(string)
});

After the initialition the rest of the promises are executed shuffled. Also remember that resolve() does not stop whatever you have inside your function to execute. It will be executed! However once you call Promise, the Promise change from Pending to Resolved and it will always return the first value inside resolve.

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.