Веб-маяк отправляет запрос перед обновлением/закрытием страницы

JavaScript Ajax
Веб-маяк отправляет запрос перед обновлением/закрытием страницы

задний план:

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

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

Однако реальность ударила меня по лицу, потому что сцена выхода со страницы — это не только переключение маршрутов~

Сцена выхода со страницы:

  1. Все еще на этом сайте, перейти к другим маршрутам
  2. Обновить страницу/закрыть страницуТакже необходимо отправить запрос на удаление задачи

Все еще на этом сайте, перейти к другим маршрутам

Это относительно просто, т.VueКрючки, которые можно отвестиbeforeRouteLeaveреализовать:

 beforeRouteLeave(to, from, next) {
    if (任务运行中) {
        // 发送请求
    }else{
        next(true) // 用户离开
    }
 }

Когда страница обновляется/закрывается:

Однако при обновлении страницыbeforeRouteLeaveОн не будет выполняться, и тогда я думаю о следующих двухAPI.

beforeunloadа такжеunload

beforeunload срабатывает, когда окно браузера закрывается или обновляется:

представлять:

использовать этотAPIМожно предотвратить прямое закрытие страницы, и пользователь может решить, не закрывать ли/обновлять текущую страницу, нажав кнопку OK/Отмена.

Под хромом это выглядит так, вы наверняка видели:

как использовать

Использование этого API очень простое, просто слушайте это событие, когда страница загружается, и когда должно появиться всплывающее окно.вернуть значение, которое можно преобразовать в true, ты сможешь.

// 页面卸载之前
let killTask = false; // 是否杀死任务
window.onbeforeunload = e => {
  if (任务运行 && 对应页面) {
    killTask = true;
    return '您可能有数据没有保存'; // 在部分浏览器可以修改弹窗标题
  } else {
    killTask = false;
  }
  // 没有return一个可以转化为true的值 就不会出现弹窗
};

Поведение браузера для этого всплывающего окна:

Следующее поведение основано на хроме:

  1. Фокус: фокус останется на этом всплывающем окне, пока вы не нажмете Отмена/ОК.

  2. Вы не можете выполнять какие-либо действия на странице, где появляется всплывающее окно.

  3. На других страницах вы можете выполнять только простые операции щелчка.Всплывающее окно по-прежнему существует в середине страницы, а клавиатуру использовать нельзя.

  4. Клавиатура: Клавиатура привязана к всплывающему окну и может быть нажата толькоEsc,Enterдля выполнения операции отмены/ОК

  5. Всплывающее окно — это не дом страницы, это поведение браузера

  6. Пользователь отменяет/подтверждает, нет API обратного вызова, нет возможности узнать

Заголовок всплывающего окна:

Заголовок обновленной страницы в хроме:重新加载此网站?

Заголовок заключительной страницы в хроме:离开此网站?

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

смущенный:

Сначала я подумал, что, поскольку операция обновления/закрытия страницы пользователем может быть перехвачена, появляется вышеуказанное всплывающее окно, и это требование выполнено.

а потом нашел,Браузер не обеспечивает обратный вызов для пользователя, чтобы нажать OK/Отмена, чтобы обновить страницу.

Здесь я потерялся, глядяbeforeunloadЭтот АПИ думает о смысле жизни (на самом деле в оцепенении), глядя на него, отbeforeunloadизbeforeЯ также подумал оunloadэтот API.

Мгновенно возрождает боевой дух, почему бы не попробовать этоunload?

unloadЭто событие запускается, когда страница выгружается

представлять

Это событие срабатывает при выгрузке страницы, это событие не может быть отменено и является необратимой операцией.

использовать

Просто слушайте событие напрямую.

window.onunload = e => {}

Комбинировать потребности:

killTaskдляbeforeunloadПеременная, определенная при вводе обратного вызова, дастkillTaskНазначение, используйте это значение, чтобы определить, когда может быть отправлен запрос на завершение задачи.

window.onunload = e => {
  if (killTask && 对应页面) {
    // 发送请求
  }
};

В этот момент все должны думать, что требование было сделано, но на самом деле это не так!

Не удалось отправить асинхронный запрос

я используюaxiosЧтобы отправить запрос, запрос был отправлен, но он был отменен, и сервер вообще не получил запрос, следующим образом.

После анализа выяснилось, чтоaxiosЗапрос асинхронный, и позже Google обнаружил, что axios не поддерживает синхронные запросы.

Наконец, используйте роднойXMLHttpRequestобъект, сделать запрос синхронным

Готово!На самом деле, это то, что я собираюсь опубликовать впервые, а следующее - лучшее решение!

Дефекты и лучшие предложения:

Когда я разместил эту статью в публичном аккаунте, я былЕженедельник странных танцевПерепечатано, некоторые из больших парней выше дали мне несколько предложений.

Немного поискал, и оказалось... хорошо! Я признаю, что я курица.

эй~ Но это одно из преимуществ ведения блога, обмена опытом и получения знаний!

Недостатки производительности:

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

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

Основываясь на проблемах с производительностью, большие ребята рекомендуютИспользуйте Beacon вместо XHR, и после некоторых поисков...

Beacon API

  1. Beacon API используется для отправки небольшого количества данных на сервер через почтовый запрос..
  2. Beaconявляется неблокирующим запросом и не требует ответа

Идеально решить проблему дефекта производительности:

  1. браузер будетBeaconЗапросы ставятся в очередь для выполнения при бездействии и немедленного возврата управления
  2. это вunloadЕго также можно отправлять асинхронно в состоянии, не блокируя обновление страницы/переход и другие операции.

так**BeaconОн может прекрасно устранить дефекты производительности, вызванные блокировкой синхронных запросов XHR, упомянутых выше**.

использовать:navigator.sendBeacon()

Полный API:

let result = navigator.sendBeacon(url, data);

Beaconвисит наnavigatorНиже, выше его полный API.

result— логическое значение, представляющее результат отправки запроса на этот раз:

  • Возвращает true, если браузер принимает запрос и ставит его в очередь.
  • Возвращает false, если во время процесса возникла проблема

navigator.sendBeaconПринимает два параметра:

  1. URL-адрес: запрошенный URL-адрес. Запрос является POST-запросом.
  2. data: данные для отправки. Типы данных могут быть: ArrayBufferView, Blob, FormData, Sting.

см. использованиеFormDataЧтобы передать каштаны данных, вы поймете:

// 创建一个新的 FormData 并添加一个键值对
let data = new FormData();
data.append('hello', 'world');
let result = navigator.sendBeacon('./src', data);
if (result) { 
  console.log('请求成功排队 等待执行');
} else {
  console.log('失败');
}

Поддержка браузера:

Поддержка браузеров: Edge: 14+, Firefox: 31+, Chrome: 39+, Opera: 26+, IE: не поддерживается.

Хотя сейчас браузерыsendBeaconПоддержка очень хорошая, и нам необходимо сделать на ней некоторую обработку совместимости:

if (navigator.sendBeacon) {
  // Beacon 代码
} else {
 // 回退到 XHR同步请求或者不做处理
}

Использование маяка в веб-воркере

потому чтоBeaconвисит наnavigatorниже, в то время как веб-воркер также имеетnavigator, я искал его, и я действительно нашел его.

Вот один из MDNкаштан, вы можете нажать, чтобы посмотреть.

PS: Студенты, не знакомые с веб-воркерами, могут прочитать мою статью.статья

Маяк другие связанные

  • Оптимизация на стороне клиента: запросы Beacon можно объединять с другими запросами и обрабатывать вместе., особенно в мобильной среде.
  • Beacon больше используется для встраивания интерфейса, мониторинга действий пользователей., и его первоначальный замысел также основан на этом.

резюме

В этой статье рассказывается о трех API,beforeunload,unloadа такжеBeacon,BeaconПо оценкам, мало кто знает этот API. В будущем, если вы столкнетесь с необходимостью встраивания внешнего интерфейса и отправки запросов перед выгрузкой страницы, не забудьте использовать эти три API.

Выше 2019.02.19

блог,Документы внешнего накопления,Нет публики,GitHub, wx:OBkoro1, Электронная почта: obkoro1@foxmail.com

Использованная литература:

MDN

Обсуждение проблемы потери статистических данных при переадресации страницы

Регистрация активности с помощью API веб-маяков