0

I have this issue where i can't make order in async foreach promise. Hope you can help me.

I have 3(promises) functions that i want to run in the foreach before running them again.

Code below:

var env = [
  'dev',
  'prd',
  'tst',
]

env.forEach(currentEnv => {
  Promise.resolve()
  .then(firstFunction(currentEnv))
  .then(secondFunction(currentEnv))
});

function firstFunction(env) {
  new Promise(resolve => {
    setTimeout(() => {
      console.log('firstFunction ' + env)
      resolve();
    }, 2000);

  }).catch((error) => {
    console.log('something went wrong' + env + "error: " + error);
  });

};

function secondFunction(env) {
  new Promise(resolve => {
    setTimeout(() => {
      console.log('secondFunction ' + env)
      resolve();

    }, 1000);
  }).catch(() => {
    console.log('something went wrong')
  });
}

Outcome:

secondFunction dev
secondFunction prd
secondFunction tst
firstFunction dev
firstFunction prd
firstFunction tst

expected:

firstFunction dev
secondFunction dev
firstFunction prd
secondFunction prd
firstFunction tst
secondFunction tst

Hope you guys can help me.

8
  • 2
    If you would, please post all the code relevant to the question in the question itself - don't hide it behind a link. You shouldn't tell potential helpers who would otherwise love to help that they have to navigate offsite just to have an idea of what you're working with. If the link breaks, the question could be rendered useless to future readers. Please edit your code into the question in a minimal reproducible example, or the question might get closed, thanks. Commented Jan 2, 2019 at 8:33
  • Your code needs to be pasted into the question itself and formatted as code. This is one of the site rules here. Commented Jan 2, 2019 at 8:35
  • You could always use a callback approach? Commented Jan 2, 2019 at 9:00
  • I defended two function renameConfigFile,runBuildScript in your code. The outcome looks exactly what you expect. Commented Jan 2, 2019 at 9:02
  • 1
    Is renameConfigFile supposed to be firstFunction and runBuildScript - secondFunction? Commented Jan 2, 2019 at 9:05

2 Answers 2

1

First of all you need to actually return promises from your functions and provide functions (not results of function calls) to .then() callbacks.

var env = [
  'dev',
  'prd',
  'tst',
]

env.forEach(currentEnv => {
  Promise.resolve()
  .then(() => firstFunction(currentEnv))
  .then(() => secondFunction(currentEnv))
});

function firstFunction(env) {
  return new Promise(resolve => {
    setTimeout(() => {
      console.log('firstFunction ' + env)
      resolve();
    }, 2000);

  }).catch((error) => {
    console.log('something went wrong' + env + "error: " + error);
  });

};

function secondFunction(env) {
  return new Promise(resolve => {
    setTimeout(() => {
      console.log('secondFunction ' + env)
      resolve();

    }, 1000);
  }).catch(() => {
    console.log('something went wrong')
  });
}

Doing that is enough to make your calls to be in order "all firstFunction() calls then all secondFunction() calls".

But if you need to make next environment to wait for the completion of work of the current one, you may use async iterator construction. It's relatively new feature, so I assume that you're using at least Node 10.x.

var env = [
  'dev',
  'prd',
  'tst',
];


function firstFunction(env) {
  return new Promise(resolve => {
    setTimeout(() => {
      console.log('firstFunction ' + env)
      resolve();
    }, 2000);

  }).catch((error) => {
    console.log('something went wrong' + env + "error: " + error);
  });

};

function secondFunction(env) {
  return new Promise(resolve => {
    setTimeout(() => {
      console.log('secondFunction ' + env)
      resolve();
    }, 1000);
  }).catch(() => {
    console.log('something went wrong')
  });
}

async function *getAsyncIterator(env) {
	for (const currentEnv of env) {
  	await firstFunction(currentEnv);
    await secondFunction(currentEnv);
    yield currentEnv;
	}
}

async function doStuff() {
  for await (const currentEnv of getAsyncIterator(env)) {
    console.log(`Complete work on ${currentEnv}`)
  }
}

doStuff();

UPDATE:

And finally, the third option is applying a recursive algorithm, in case when some older node version must be supported.

var env = [
  'dev',
  'prd',
  'tst',
];

function firstFunction(env) {
  return new Promise(resolve => {
    setTimeout(() => {
      console.log('firstFunction ' + env)
      resolve();
    }, 2000);

  }).catch((error) => {
    console.log('something went wrong' + env + "error: " + error);
  });

};

function secondFunction(env) {
  return new Promise(resolve => {
    setTimeout(() => {
      console.log('secondFunction ' + env)
      resolve();
    }, 1000);
  }).catch(() => {
    console.log('something went wrong')
  });
}

function doStuff(env = []) {
	if (env.length === 0) return;
  
	const [ currentEnv, ...restEnvs ] = env;
  
	return Promise.resolve()
  	.then(() => firstFunction(currentEnv))
    .then(() => secondFunction(currentEnv))
    .then(() => doStuff(restEnvs));
}

doStuff(env).then(() => console.log('job done'));

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

3 Comments

Thank you very much. i can use this. but i have a problem. when a user with a lower version of node it throws an error: SyntaxError: Unexpected token * and i can't seems to catch these, to writeout a console for the user to ask them nicely to upgrade to version < 10
i came up with this solution. if(process.versions.node.split('.').shift() >= 10) { console.log('test') var processBuild = require('./process.js'); }
@Silo Also you can checkout the updated version of my answer. It includes another option of algorithm, which doesn't include async iterator, but still makes the job done. So it must work on all versions of Node that support promises.
0

Hi and thank you so much guys for your help. I have been playing a little and came up with this solution:

let promise = Promise.resolve();
env.forEach(thisEnv => {
  promise = promise
    .then(() => firstFunction(thisEnv))
    .then(() => secondFunction(thisEnv))
});

promise.then(() => {
  doneBuilding()
});

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.