Вызов функции на стороне сервера перед выгрузкой (firebase)

Я пытаюсь сохранить пользовательские данные, когда запускается событие JavaScript «перед выгрузкой». Я вызываю серверную функцию (облачные функции firebase), которая просто получает объект от пользователя и обновляет документ. Функция срабатывает, но из консоли firebase я вижу, что она завершена с кодом 204. Вот мой клиентский код

window.onbeforeunload = function() {
    firefun_ref(data);
}

Сторона сервера:

exports.updateStats = functions.https.onCall(async (data, context) => {
  return admin.firestore().collection("stats")
    .doc((new Date()).toISOString().substring(0, 10))
    .update(filter(data));
});

Я хочу отметить, что если я запускаю функцию саму по себе, она работает нормально, просто вызывает проблемы, когда она находится в событии перед выгрузкой.

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
0
39
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Это будет невозможно.

Браузеры строго ограничивают то, что вам разрешено делать на мероприятии beforeunload, потому что это может привести к злоупотреблениям. Асинхронные события не допускаются (поскольку они могут заставить окно оставаться открытым в течение произвольного периода времени после того, как пользователь захочет его закрыть).

Насколько мне известно, единственным надежным использованием onbeforeunload является отображение подсказки, позволяющей пользователю передумать; некоторые браузеры позволят вам настроить отображаемый текст (путем возврата строки из обработчика beforeunload), некоторые браузеры всегда будут отображать текст по умолчанию:

window.addEventListener('beforeunload', function (e) {
  // Cancel the event
  e.preventDefault(); // If you prevent default behavior in Mozilla Firefox prompt will always be shown
  // Chrome requires returnValue to be set
  e.returnValue = '';
});

https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onbeforeunload

Так нет ли способа сохранить данные в фоновом режиме, когда пользователь уходит?

Johnson 16.03.2022 22:36

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

Daniel Beck 16.03.2022 22:37

Если данные, которые вы хотите записать, известны до того, как пользователь закроет вкладку, вы можете зарегистрировать так называемый onDisconnect обработчик в базе данных реального времени (другая база данных, которая является частью Firebase).

Обработчик onDisconnect — это операция отложенной записи, которая запускается, как только сервер замечает, что клиент отключился, либо потому, что SDK в этом клиенте сообщает об этом перед отключением, либо потому, что время ожидания сокета на сервере истекло (что может занять несколько минут). ).

В Firestore не существует эквивалента, потому что его проводной протокол не требует установления соединения, а база данных реального времени работает на основе (веб-сокетов). Если вы хотите интегрировать это в Firestore, ознакомьтесь с документацией по создание системы присутствия в Firestore с использованием базы данных реального времени.

Я пытаюсь заставить это работать с API маяка и даже нашел хук:

/*
  see https://developer.mozilla.org/en-US/docs/Web/API/Navigator/sendBeacon
  
  ```jsx
  const MyComponent = ({ children }) => {
    // will get fired if the page unloads while the component is mounted
    useUnloadBeacon({
      url: 'https://api.my.site/route',
      payload: () => {
        return 'something'
      }
    })
    
    return children
  }
  ```
*/

import { useEffect } from "react"

export const useUnloadBeacon = ({
  url = "",
  payload = () => {},
}) => {
  const eventHandler = () => navigator.sendBeacon(url, payload())

  useEffect(() => {
    window.addEventListener("unload", eventHandler, true)
    return () => {
      window.removeEventListener("unload", eventHandler, true)
    }
  }, [])
}

Единственная проблема, с которой я сталкиваюсь, - это запуск облачной функции. Я отправляю запрос на получение, но он почему-то не срабатывает.

Облачная функция

app.post("/setStatusToOpen", setStatusToOpen)

const setStatusToOpen = async (req, res) => {
  console.info("setStatusToOpen, req.query", req.query)
  const { documentId } = req.query
  try {
    const setPayload = { status: "open" }
    firestore
      .doc(`messageInABottle/${documentId}`)
      .set(setPayload, { merge: true })

    return res.send(true)
  } catch (error) {
    console.info("Error in getMessageInABottleRecipient:", error)
    return res.send(error)
  }
}

Я думаю, что это как-то связано с неправильными заголовками.

Другие вопросы по теме