@karpo518

Как получить результат из асинхронной функции в javascript?

Мне нужно добиться, чтобы функция push_updateSubscription в приложенном скрипте работала асинхронно, но ничего не получается. Изначально этот код дергал скрипт на сервере с помощью fetch, не дожидаясь ответа и не интересуюясь содержимым этого ответа.

Сейчас мне нужно иметь возможность получить ответ от сервера из функции push_updateSubscription. Я плохо знаком с нативным javascript. Я уловил общий принцип использования асинхронных функций, но использование then и события serviceWorker.ready осложняет ситуацию.

В итоге я добавил в нескольких местах async и await. Мне удалось получить ответ из fetch в функции push_updateSubscription, но асинхронно вернуть его дальше не получается. То есть код await push_updateSubscription() возвращает undefined. Просьба подсказать, в чём ошибка. А также подсказать, есть ли в коде лишние await и async.

Проблемный скрипт
document.addEventListener('DOMContentLoaded', () => {
  const applicationServerKey =
    'какой-то ключ';
  let isPushEnabled = false;

  if (!('serviceWorker' in navigator)) {
    console.warn('Service workers are not supported by this browser');
    //changePushButtonState('incompatible');
    return;
  }

  if (!('PushManager' in window)) {
    console.warn('Push notifications are not supported by this browser');
    //changePushButtonState('incompatible');
    return;
  }

  if (!('showNotification' in ServiceWorkerRegistration.prototype)) {
    console.warn('Notifications are not supported by this browser');
    //changePushButtonState('incompatible');
    return;
  }

  // Check the current Notification permission.
  // If its denied, the button should appears as such, until the user changes the permission manually
  if (Notification.permission === 'denied') {
    console.warn('Notifications are denied by the user');
    //changePushButtonState('incompatible');
    return;
  }

  navigator.serviceWorker.register('/local/web-push/serviceWorker.js').then(
    async() => {
      console.log('[SW] Service worker has been registered');
      let result = await push_updateSubscription();
      console.log(result);
    },
    e => {
      console.error('[SW] Service worker registration failed', e);
      //changePushButtonState('incompatible');
    }
  );

  function urlBase64ToUint8Array(base64String) {
    const padding = '='.repeat((4 - (base64String.length % 4)) % 4);
    const base64 = (base64String + padding).replace(/\-/g, '+').replace(/_/g, '/');

    const rawData = window.atob(base64);
    const outputArray = new Uint8Array(rawData.length);

    for (let i = 0; i < rawData.length; ++i) {
      outputArray[i] = rawData.charCodeAt(i);
    }
    return outputArray;
  }

  function checkNotificationPermission() {
    return new Promise((resolve, reject) => {
      if (Notification.permission === 'denied') {
        return reject(new Error('Push messages are blocked.'));
      }

      if (Notification.permission === 'granted') {
        return resolve();
      }

      if (Notification.permission === 'default') {
        return Notification.requestPermission().then(result => {
          if (result !== 'granted') {
            reject(new Error('Bad permission result'));
          }

          resolve();
        });
      }
    });
  }

  function push_subscribe() {
    //changePushButtonState('computing');

    return checkNotificationPermission()
      .then(() => navigator.serviceWorker.ready)
      .then(serviceWorkerRegistration =>
        serviceWorkerRegistration.pushManager.subscribe({
          userVisibleOnly: true,
          applicationServerKey: urlBase64ToUint8Array(applicationServerKey),
        })
      )
      .then(subscription => {
        // Subscription was successful
        // create subscription on your server
        return push_sendSubscriptionToServer(subscription, 'POST');
      })
      .catch(e => {
        if (Notification.permission === 'denied') {
          // The user denied the notification permission which
          // means we failed to subscribe and the user will need
          // to manually change the notification permission to
          // subscribe to push messages
          console.warn('Notifications are denied by the user.');
          changePushButtonState('incompatible');
        } else {
          // A problem occurred with the subscription; common reasons
          // include network errors or the user skipped the permission
          console.error('Impossible to subscribe to push notifications', e);
          changePushButtonState('disabled');
        }
      });
  }

  

  async function push_updateSubscription() {
    navigator.serviceWorker.ready
      .then(async(serviceWorkerRegistration) => serviceWorkerRegistration.pushManager.getSubscription())
      .then(async(subscription) => {

        if (!subscription) {
          push_subscribe();
          return;
        }

        // Keep your server in sync with the latest endpoint
        let response = await push_sendSubscriptionToServer(subscription, 'PUT');
        console.log(response);

        return response;
      })
      .catch(e => {
        console.error('Error when updating the subscription', e);
      });
  }

  async function push_sendSubscriptionToServer(subscription, method) {
    const key = subscription.getKey('p256dh');
    const token = subscription.getKey('auth');
    const contentEncoding = (PushManager.supportedContentEncodings || ['aesgcm'])[0];

    let response = await fetch('/local/web-push/push_subscription.php', {
      method,
      headers: {
        'Content-Type': 'application/json;charset=utf-8'
      },
      body: JSON.stringify({
        endpoint: subscription.endpoint,
        publicKey: key ? btoa(String.fromCharCode.apply(null, new Uint8Array(key))) : null,
        authToken: token ? btoa(String.fromCharCode.apply(null, new Uint8Array(token))) : null,
        contentEncoding,
      }),
    });

    console.log(response);

    return response;
  }

});
  • Вопрос задан
  • 126 просмотров
Решения вопроса 1
Aetae
@Aetae Куратор тега JavaScript
Тлен
navigator.serviceWorker.ready -> return navigator.serviceWorker.ready :)
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

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

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