Как использовать синхронизацию в асинхронном Promise в JavaScript? - PullRequest
0 голосов
/ 03 февраля 2019

Когда я запускаю следующий код:

b = async attempt => {
  if (attempt == 5) {
    return;
  }
  console.log("Starting attempt:", attempt);
  b(attempt + 1).then(() => {
    console.log("Finished attempt:", attempt);
  });
};
b(0);

Вывод:

Starting attempt: 0
Starting attempt: 1
Starting attempt: 2
Starting attempt: 3
Starting attempt: 4
Finished attempt: 4
Finished attempt: 3
Finished attempt: 2
Finished attempt: 1
Finished attempt: 0

Однако я хочу вызывать еще одно обещание a перед каждым рекурсивным вызовом следующим образом:

a = Promise.resolve();
b = async attempt => {
  if (attempt == 5) {
    return;
  }
  console.log("Starting attempt:", attempt);
  a.then(() => {
    b(attempt + 1);
  }).then(() => {
    console.log("Finished attempt:", attempt);
  });
};
b(0);

Теперь вывод:

Starting attempt: 0
Starting attempt: 1
Starting attempt: 2
Finished attempt: 0
Starting attempt: 3
Finished attempt: 1
Starting attempt: 4
Finished attempt: 2
Finished attempt: 3
Finished attempt: 4

Как я могу изменить второй блок кода, чтобы убедиться, что вывод совпадает с первым блоком кода?

Ответы [ 3 ]

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

Вы нарушаете цепочку обещаний, не возвращая внутреннее обещание a.then(() => {b(attempt + 1);}).Добавление оператора возврата должно помочь.

Также я бы рекомендовал не смешивать синтаксис async/await с .then и обратными вызовами.

Следующий код выглядит более "синхронно" и делает свое дело.

const a = Promise.resolve();
const b = async attempt => {
  if (attempt == 5) {
    return;
  }
  console.log("Starting attempt:", attempt);
  
  await a
  
  await b(attempt + 1)
  
  console.log(`Finished attempt: ${attempt}`)
};

b(0);
0 голосов
/ 03 февраля 2019

Вы забыли return цепочки обещаний, которые вы создаете:

const b = attempt => {
  if (attempt == 5) {
    return Promise.resolve();
  }
  console.log("Starting attempt:", attempt);
  const a = Promise.resolve();
  return a.then(() => {
//^^^^^^
    return b(attempt + 1);
//  ^^^^^^
  }).then(() => {
    console.log("Finished attempt:", attempt);
  });
};
b(0).then(() => {
  console.log("done");
});

Только с этими return с вызывающая функция сможет ждать обещание.Ваш первый фрагмент имеет ту же проблему.Было бы более очевидно, если бы вы пропустили ключевое слово async, чтобы было ясно, что b() не возвращает обещание.

Если вы хотите использовать async / await, ваш код должен выглядеть так:

const b = async attempt => {
  if (attempt == 5) {
    return;
  }
  console.log("Starting attempt:", attempt);
  await Promise.resolve();
//^^^^^
  await b(attempt + 1);
//^^^^^
  console.log("Finished attempt:", attempt);
};
b(0).then(() => {
  console.log("done");
});
0 голосов
/ 03 февраля 2019

Если я правильно понимаю ваш вопрос, то проблема вызвана вложенными обещаниями и вызовами асинхронных функций (т.е. b(attempt + 1)), не блокирующих выполнение включающей функции.Это, в свою очередь, приводит к неупорядоченным и неожиданным результатам регистрации.

Рассмотрите возможность изменения вызова на b(), на return обещание b(attempt + 1);, чтобы обеспечить выполнение следующего журнала: console.log("Finished attempt:", attempt) после завершенияиз b() завершено:

const a = Promise.resolve();
const b = async attempt => {
  if (attempt == 5) {
    return;
  }
  console.log("Starting attempt:", attempt);
  
  await a.then(() => {
  
    /* 
    Return the project of b() here, has similar effect
    to that of await keyword
    */
    return b(attempt + 1); 
  }).then(() => {
    console.log("Finished attempt:", attempt);
  });
};

b(0);
...