Как правильно использовать async/await?

Мне нужно что бы функции отработали в соответствии с порядком вызова. Добавил async/await но, это не помогло. Как его правильно использовать?

Функция analyze переберает массив и вызывает записаные в него функции и сумирует результат.

Функция initFingerprintJS должна вернуть значение,но, я з JS знаком плохо и поэтому запустался в этих callback'ах, промисах и async/await. Поэтому решил напрямую писать в переменную.

Желаемый результат: START -> ANALYZE (c:0, c:1) -> SET ID -> ID -> END

const counters = [
  function() {
    return navigator.webdriver ? 5 : 0;
  },
  function() {
    let agent = window.navigator.userAgent;

    if (/headless/i.test(agent) || /PhantomJS/i.test(agent)) {
      return 3;
    }

    return 0;
  },
  function() {
    navigator.permissions.query({
      name: 'notifications'
    }).then(function(permissionStatus) {
      if (Notification.permission === 'denied' && permissionStatus.state === 'prompt') {
        return 10;
      }
    });

    return 0;
  }
];

let id;

window.addEventListener('DOMContentLoaded', async function() {
  console.log('START');

  let res = await analyze();

  initFingerprintJS();

  console.log('ID: ' + id);

  console.log('END');
});

async function analyze() {
  let r = 0;

  counters.forEach((v, k) => {
    console.log('c: ' + k);
    r += v();
  });

  return r;
}


function initFingerprintJS() {
  let fpPromise =
    import ('https://openfpcdn.io/fingerprintjs/v3')
    .then(FingerprintJS => FingerprintJS.load({
      region: 'eu'
    }));

  fpPromise
    .then(fp => fp.get())
    .then(result => {
      console.log('SET ID');
      id = result.visitorId;
    });
}


Ответы (1 шт):

Автор решения: Grundy

сам по себе async ничего не дает. Для правильной работы нужно расставить еще и await.

Для того чтобы использовать await функция должна возвращать Promise, который и будет ожидаться.

В коде в вопросе ни одна из функций не возвращает Promise, соответственно и дождаться выполнения невозможно.

Самое простое решения для initFingerprintJS. Достаточно добавить return.

return fpPromise

Две оставшиеся функции нужно переделать так, чтобы они возвращали Promise.

На примере с setTimeout.

function analyze() {
  return new Promise(r => // создаем новый Promise
    setTimeout(
      () => r(console.log('ANALYZE')), // вызываем `r` переводя `Promise` в состояние resolved
      1000));
}

Теперь в основной функции нужно добавить недостающие await

await setFingerPrint();

Так как в analyze нет асинхронных операций, то нет смысла добавлять async для этой функции.

Пример в сборе:

const counters = [
  function() {
    return 1;
  },
  function() {
    return 2;
  }
];

let id;

window.addEventListener('DOMContentLoaded', async function() {
  console.log('START');

  analyze();

  await setFingerPrint();

  console.log('END')
});

function analyze() {
  let r = 0;

  counters.forEach((v, k) => {
    console.log('c: ' + k);
    r += v();
  });

  return r;
}

function setFingerPrint() {
  return new Promise(r => {
    if (window.requestIdleCallback) {
      requestIdleCallback(() => r(initFingerprintJS()));
    } else {
      setTimeout(() => r(initFingerprintJS()), 500);
    }
  });
}

function initFingerprintJS() {
  let fpPromise =
    import ('https://openfpcdn.io/fingerprintjs/v3')
    .then(FingerprintJS => FingerprintJS.load({
      region: 'eu'
    }));

  return fpPromise
    .then(fp => fp.get())
    .then(result => {
      console.log('SET ID');
    });
}

→ Ссылка