foreach асинхронный с несколькими функциями - PullRequest
0 голосов
/ 02 января 2019

У меня есть проблема, когда я не могу сделать заказ в асинхронном режиме. Надеюсь, ты сможешь мне помочь.

У меня есть 3 (обещания) функции, которые я хочу запустить в foreach, прежде чем запускать их снова.

Код ниже:

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')
  });
}

Результат:

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

ожидается

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

Надеюсь, вы, ребята, можете мне помочь.

Ответы [ 2 ]

0 голосов
/ 03 января 2019

Привет и большое спасибо, ребята, за вашу помощь.Я немного поиграл и придумал это решение:

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

promise.then(() => {
  doneBuilding()
});
0 голосов
/ 02 января 2019

Прежде всего вам нужно на самом деле вернуть обещания из ваших функций и предоставить функции (не результаты вызовов функций) для .then() обратных вызовов.

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')
  });
}

Этого достаточно, чтобы ваши звонки были в порядке "все firstFunction() звонки, затем все secondFunction() звонки".

Но если вам нужно создать следующую среду для ожидания завершения работы текущей, вы можете использовать асинхронную конструкцию итератора. Это относительно новая функция, поэтому я предполагаю, что вы используете хотя бы 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:

И, наконец, третий вариант - применение рекурсивного алгоритма в случае, если требуется поддержка более старой версии узла.

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'));
...