Обратный отсчет JavaScript, чтобы наступить на сбор ямы

WeChat браузер
Обратный отсчет JavaScript, чтобы наступить на сбор ямы

Некоторое время назад в проект был добавлен обратный отсчет.

复制粘贴干

Три клика, готово, отправляйте на тестирование

let countdown = 100000; // ms 服务器返回的倒计时剩余时间

function startCountdown() {
    setTimeout({
        countdown -= 1000;
        if (/* some */) {
            // do some
            startCountdown();
        }
    }, 1000);
}

Развитие определенного цвета пера: я буду есть ши, когда в этой волне будут жуки.

Затем испытательница дала мне несколько ударов слеваbug

哭

  • bug1: Вы не правы, смотрел несколько минут, была задержка в несколько секунд
  • bug2: С вами что-то не так, я сжимаю браузер, жду какое-то время и снова открываю, он задерживается на несколько минут

Развитие определенного цвета пера: Невозможно, я снова проверю себя и дам вам пощечину, когда я тестировал его, проблем, очевидно, не было.

Пять минут спустя: ах, ах, ах ~ эммммммммм....

Хорошо, я изменю это.

причина

Задача таймера в браузере неточна, поэтому мы часто говорим о том, почему setTimeout неточен. Это касается js single thread и механизма запуска. Если вам интересно, вы можете узнать об этом, во многих статьях это было представлено.

В моем коде причина ошибки:

  • Суперпозиция ошибок не считается, то есть ошибки не обрабатываются
  • Не учитывает «сон» браузера

иметь дело с

1. Наложение ошибок не учитывается, т.е. ошибки не обрабатываются

Сначала взгляните на оптимизированный код.

let countdown = 100000; // ms 服务器返回的倒计时剩余时间
let countIndex = 1; // 倒计时任务执行次数
const timeout = 1000; // 触发倒计时任务的时间间隙
const startTime = new Date().getTime();

startCountdown(timeout);

function startCountdown(interval) {
  setTimeout(() => {
    const endTime = new Date().getTime();
    // 偏差值
    const deviation = endTime - (startTime + countIndex * timeout);
    console.log(`${countIndex}: 偏差${deviation}ms`);
    
    countIndex++;
    
    // 下一次倒计时
    startCountdown(timeout - deviation);
  }, interval);
}

Логики для быстрого выполнения почти нет, уже есть средняя задержка 5 мс в секунду, поэтому задержка в 10 минут в сумме составит 3000 мс.

Ошибки обратного отсчета неизбежны, но мы можем максимально минимизировать эту ошибку.

// 下次倒计时任务执行的等待时间 = 1s - 误差
startCountdown(timeout - deviation);

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

2. Не считает браузер "спящим"

On most browsers inactive tabs have low priority execution and this can affect JavaScript timers.

Перевод на моем ломаном английском: В большинстве браузеров неактивные вкладки имеют более низкий приоритет, что влияет на таймеры JavaScript.

Большинство вышеперечисленных браузеров не включают IE и не имеют этой проблемы в IE (т.е. настолько просты в использовании).

Дерьмо + Резюме: для экономии энергии мы установили задержку таймера в миллисекундах >= 1000 мс для вкладок, работающих в фоновом режиме.

Ссылки по теме:

Для второй точки

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

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

Пример, полученный из моих потребностей:

  • На веб-странице реализована функция обратного отсчета на 5 дней.
  • Остаток обратного отсчета получается по запросу, начальное значение 432000(s), что составляет 5 дней, и на стороне сервера также будет выполняться обратный отсчет

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

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

В настоящее время существует два варианта мониторинга:

Для window.focus + window.blur, даже если веб-страница все еще отображается пользователю, это событие будет инициировано, например, переключение из браузера в чат WeChat (веб-страница в это время все еще видна), но window. событие размытия все равно будет запущено.

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

// 处理页面可见属性的改变
document.addEventListener('visibilityChange', () => {
    if (!document.hidden) {
      // get newest downtime
    }
});

Суммировать

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

Но requestAnimationFrame, похоже, не может решить и второй случай:

Web Worker проиграет его через два дня, но я еще этого не сделал.

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