@Shimpanze

Объясните, почему не срабатывает await?

Добрый день!

Пытаюсь разобраться с asinc - await. Почему не срабатывает вот эта конструкция, которая должна выводить в консоли, последовательно цифры 1, 2, 3?

async function my_function() {
  console.log('1');
  await setTimeout(() => { console.log('2'); }, 1000);
  await console.log('3');
}


Спасибо!
  • Вопрос задан
  • 474 просмотра
Решения вопроса 3
bingo347
@bingo347 Куратор тега JavaScript
Crazy on performance...
Потому что await работает только с Promise-like объектами, то есть объектами имеющими метод then()
Под капотом await работает примерно следующим образом:
// пусть value - результат операции справа от await
// resolve - функция, которая получает 1 аргумент, который вернет await
// (но не раньше выполнения микротасков event loop)
// reject - функция, которая получает 1 аргумент, который пробросит исключение в await
// (но не раньше выполнения микротасков event loop)
if(value && typeof value.then === 'function') {
  value.then(resolve, reject);
} else {
  resolve(value);
}

Про event loop, а так же что в нем микротаски - гуглите. Скажу лишь одно, микротаски выполняются на каждой итерации event loop притом все сразу, пока не закончатся.

console.log синхронный, оборачивание его в await не даст результата, кроме разве что следующее действие (которого в примере нет) будет выполнено в следующем микротаске, но по сути сразу же
setTimeout - асинхронный, но на колбэках, необходимо либо обернуть его в Promise либо в Promise-like объект.
Вариант с Promise:
async function my_function() {
  console.log('1');
  await new Promise(resolve => setTimeout(resolve, 1000));
  console.log('2');
  console.log('3');
}

Вариант с Promise-like:
async function my_function() {
  console.log('1');
  await {then(resolve) { setTimeout(resolve, 1000); }};
  console.log('2');
  console.log('3');
}
Ответ написан
Комментировать
rockon404
@rockon404
Frontend Developer
О причине вам уже написали. Поделюсь примером как заставить ваш код работать:
async function my_function() {
  console.log('1');
  await new Promise(resolve => {
    setTimeout(() => {
      console.log('2');
      resolve();
    }, 1000);
  });
  console.log('3');
}


Или можно вынести функцию setAsyncTimeout:
function setAsyncTimeout(cb, timeout) {
  return new Promise(resolve => {
    setTimeout(() => {
      cb();
      resolve();
    }, timeout);
  });
}

async function my_function() {
  console.log('1');
  await setAsyncTimeout(() => { console.log('2'); }, 1000);
  console.log('3');
}
Ответ написан
Комментировать
SagePtr
@SagePtr
Еда - это святое
Потому что setTimeout и console.log не асинхронные. Вернее, setTimeout - асинхронный, но не через механизм async/await (сахар для Promise), а через колбэк, передающийся первым параметром (потому чтобы использовать его через await - нужно будет завернуть его в функцию, возвращающую promise)
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
mylp
@mylp
php + js = site + crm
потому что setTimeout это не асинхронная функция и консолька тож. Посмотрите EventLoop JS
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы