setInterval () не работает до скорости - PullRequest
0 голосов
/ 12 мая 2019

Я создаю галерею на сайте, над которым я работаю. Он прокручивает фотографии автоматически, но пользователь также может сделать паузу и прокрутить вручную. Проблема, с которой я столкнулся, заключается в автоматическом режиме прокрутки. Я набрал setInterval() для запуска autoScroll() каждую миллисекунду. В autoScroll() она увеличивает переменную, затем прокручивает и устанавливает переменную обратно в 0, когда переменная достигает 3000. Я делаю это так, вместо того чтобы использовать 3000 миллисекунд для setInterval, который напрямую вызывает прокрутку, чтобы я мог сбросить таймер, когда пользователь делает паузу или прокручивает вручную. По идее, она должна прокручиваться каждые 3 секунды. Но это намного медленнее, чем это. В Chrome это занимает около 12 секунд, а в Firefox - около 45 секунд. Я еще не тестировал его в других браузерах.

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

Вот соответствующий HTML-код, на который ссылается скрипт:

<table>
  <tr>
    <th>
      <button id="left">&#10094;</button>
    </th>
    <th id="picture" colspan="3"></th>
    <th>
      <button id="right">&#10095;</button>
    </th>
  </tr>
  <tr>
    <td></td>
    <td id="pause">&#10074;&#10074;</td>
    <td id="below"><span id="caption" style="text-align: center;"></span><br><span id="dots"
        style="text-align: center;"></span></td>
    <td style="width: 5%"></td>
    <td></td>
  </tr>
</table>

А вот и JavaScript:

var pics = ["pic1.jpg", "pic2.jpg", "pic3.jpg", "pic4.jpg", "pic5.jpg"];
var captions = ["caption 1", "caption 2", "caption 3", "caption 4", "caption 5",];
var play = true;
var position = 0;
var direction = 0;
var auto = 0;

for (var x = 1; x < pics.length + 1; x++) {
  dots.innerHTML = dots.innerHTML + '<input id="dot' + x.toString() + '" type="radio" name="dot" value="' + x.toString() + '"><label for="dot' + x.toString() + '">&#9679;</label>';
}

dot1.checked = true;
picture.innerHTML = '<img src="' + pics[0] + '" />';
caption.innerHTML = captions[0];

function move() {
  var positionIndex = position + 1;
  position = position + direction;
  if (position == -1) { position = pics.length - 1; }
  if (position == pics.length) { position = 0; }
  positionIndex = position + 1;
  picture.innerHTML = '<img src="' + pics[position] + '" />';
  caption.innerHTML = captions[position];
  document.getElementById("dot" + positionIndex.toString()).checked = true;
  auto = 0;
}

left.onclick = function () {
  direction = -1;
  move();
}

right.onclick = function () {
  direction = 1;
  move();
}

dots.onclick = function () {
  position = parseInt(document.querySelector('input[name = "dot"]:checked').value) - 1;
  positionIndex = position + 1;
  picture.innerHTML = '<img src="' + pics[position] + '" />';
  caption.innerHTML = captions[position];
  document.getElementById("dot" + positionIndex.toString()).checked = true;
  auto = 0;
}

pause.onclick = function () {
  if (play) {
    play = false;
    pause.innerHTML = "&#9654;";
  } else {
    play = true;
    pause.innerHTML = "&#10074;&#10074;";
  }
  auto = 0;
}

function autoScroll() {
  auto++
  if (auto == 3000 && play) {
    direction = 1;
    auto = 0;
    move();
  }
}

window.setInterval(autoScroll, 1);

1 Ответ

1 голос
/ 12 мая 2019

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

https://developers.google.com/web/updates/2018/02/meltdown-spectre

Даже до этого setInterval никогда не гарантировал, что сработает точно по истечении указанного времени. Если браузер будет занят, это может ухудшиться.

Короче говоря, вместо увеличения переменной на 1 каждый setInterval, вы должны проверить текущее время (например, с помощью + (new Date ())) и посмотреть, сколько времени действительно прошло.

  ...
  auto = +(new Date());
}
function autoScroll() {
  var date = +(new Date());
  if(auto > date + 3000 && play) {
    direction = 1;
    auto = date;
    move();
  }
}

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

  ...
  resetTimer();
}
function autoScroll() {
  if(play) {
    direction = 1;
    resetTimer();
    move();
  }
}
function resetTimer() {
   if(timer) {
       window.clearInterval(timer);
   }
   timer = window.setInterval(autoScroll,3000);
}
timer = window.setInterval(autoScroll,3000);
...