задний план:
Есть задача, которая очень трудоемка и потребляет много вычислительной мощности в фоновом режиме, поэтому при выходе со страницы попросите фронтенд отправить запрос на убийство задачи.
Сначала я думал, что это требование очень простое, просто отправьте запрос и убейте задачу, прежде чем вводить другие маршруты.
Однако реальность ударила меня по лицу, потому что сцена выхода со страницы — это не только переключение маршрутов~
Сцена выхода со страницы:
- Все еще на этом сайте, перейти к другим маршрутам
- Обновить страницу/закрыть страницуТакже необходимо отправить запрос на удаление задачи
Все еще на этом сайте, перейти к другим маршрутам
Это относительно просто, т.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的值 就不会出现弹窗
};
Поведение браузера для этого всплывающего окна:
Следующее поведение основано на хроме:
-
Фокус: фокус останется на этом всплывающем окне, пока вы не нажмете Отмена/ОК.
-
Вы не можете выполнять какие-либо действия на странице, где появляется всплывающее окно.
-
На других страницах вы можете выполнять только простые операции щелчка.Всплывающее окно по-прежнему существует в середине страницы, а клавиатуру использовать нельзя.
-
Клавиатура: Клавиатура привязана к всплывающему окну и может быть нажата только
Esc
,Enter
для выполнения операции отмены/ОК -
Всплывающее окно — это не дом страницы, это поведение браузера
-
Пользователь отменяет/подтверждает, нет 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
- Beacon API используется для отправки небольшого количества данных на сервер через почтовый запрос..
Beacon
является неблокирующим запросом и не требует ответа
Идеально решить проблему дефекта производительности:
- браузер будет
Beacon
Запросы ставятся в очередь для выполнения при бездействии и немедленного возврата управления - это в
unload
Его также можно отправлять асинхронно в состоянии, не блокируя обновление страницы/переход и другие операции.
так**Beacon
Он может прекрасно устранить дефекты производительности, вызванные блокировкой синхронных запросов XHR, упомянутых выше**.
использовать:navigator.sendBeacon()
Полный API:
let result = navigator.sendBeacon(url, data);
Beacon
висит наnavigator
Ниже, выше его полный API.
result
— логическое значение, представляющее результат отправки запроса на этот раз:
- Возвращает true, если браузер принимает запрос и ставит его в очередь.
- Возвращает false, если во время процесса возникла проблема
navigator.sendBeacon
Принимает два параметра:
- URL-адрес: запрошенный URL-адрес. Запрос является POST-запросом.
- 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
Использованная литература:
Обсуждение проблемы потери статистических данных при переадресации страницы