Какова максимальная скорость, с которой события запускаются в веб-браузере? - PullRequest
0 голосов
/ 03 июня 2018

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

Мне было бы интересно узнать, какова максимальная частота срабатываний событий для веб-браузера и указывается ли это в каком-то стандарте (например, связанном с ES6).

Ситуация для тех, кому интересно: Grid With Intervals

Ответы [ 3 ]

0 голосов
/ 03 июня 2018

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

Посмотрите, я нарисовал на этом холсте две линии точек в фиксированной позиции Y и в текущей позиции X.Верхний обновлялся, поскольку цикл while был настолько частым, насколько мог сценарий, другой был нарисован с помощью события mouseMoved.Как видите, результат практически одинаков (даже точки в MouseMove иногда бывают чаще) Сравнение точностей точек Время, которое требуется обработчику событий, сильно влияет, на самом деле я сделалметод ожидания в течение 1 секунды, а затем рисования, и в результате были получены точки с шагом 5 см, которые перемещали мышь с той же скоростью.

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

0 голосов
/ 03 июня 2018

Использование <canvas> может помочь вам добиться более плавного поведения:

const scale = window.devicePixelRatio || 1;
const unit = 8;
const scaledUnit = unit * scale;
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const offsetLeft = canvas.offsetLeft;
const offsetTop = canvas.offsetTop;

let drawing = false;

canvas.setAttribute('width', canvas.offsetWidth * scale);
canvas.setAttribute('height', canvas.offsetHeight * scale);

canvas.onmousedown = (e) => {
  drawing = true;
  
  paintPixel(Math.floor((e.pageX - offsetLeft) / unit), Math.floor((e.pageY - offsetTop) / unit));
};

canvas.onmouseup = (e) => {
  drawing = false;
};

canvas.onmousemove = (e) => {
  if (drawing) {
    paintPixel(Math.floor((e.pageX - offsetLeft) / unit), Math.floor((e.pageY - offsetTop) / unit));
  }
};

canvas.onmouseleave = (e) => {
  paint = false;
};

function paintPixel(x, y) {
  ctx.fillRect(x * scaledUnit, y * scaledUnit, scaledUnit, scaledUnit);
}
body {
  margin: 0;
  font-size: 0;
}

#canvas {
  width: 100%;
  height: 100vh;
}
<canvas id="canvas"></canvas>

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

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

const scale = window.devicePixelRatio || 1;
const unit = 8;
const scaledUnit = unit * scale;
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const offsetLeft = canvas.offsetLeft;
const offsetTop = canvas.offsetTop;

let drawing = false;
let lastX = null;
let lastY = null;

canvas.setAttribute('width', canvas.offsetWidth * scale);
canvas.setAttribute('height', canvas.offsetHeight * scale);

canvas.onmousedown = (e) => {
  drawing = true;
  lastX = Math.floor((e.pageX - offsetLeft) / unit);
  lastY = Math.floor((e.pageY - offsetTop) / unit);
  
  paintPixel(lastX, lastY);
};

canvas.onmouseup = (e) => {
  drawing = false;
};

canvas.onmousemove = (e) => {
  if (drawing) {
    const x = Math.floor((e.pageX - offsetLeft) / unit);
    const y = Math.floor((e.pageY - offsetTop) / unit);
    const w = Math.abs(x - lastX);
    const h = Math.abs(y - lastY);
    
    if (w === 0 && h === 0) {
      paintPixel(x, y);
    } else if (w > h) {
      lineLandscape(lastX, lastY, x, y);
    } else {
      linePortrait(lastX, lastY, x, y);
    }
  
    lastX = x;
    lastY = y;
  }
};

canvas.onmouseleave = (e) => {
  paint = false;
};

function paintPixel(x, y) {
  ctx.fillRect(x * scaledUnit, y * scaledUnit, scaledUnit, scaledUnit);
}

function lineLandscape(x0, y0, x1, y1) {
  if (x0 > x1) {
    [x0, x1] = [x1, x0];
    [y0, y1] = [y1, y0];
  }
  
  const dx = x1 - x0;
  const dy = Math.abs(y1 - y0);
  const yi = y0 > y1 ? -1 : 1;
  
  let D = 2 * dy - dx;  
  let y = y0;

  for (let x = x0; x <= x1; ++x) {
    paintPixel(x, y);
    
    if (D > 0) {
      y += yi;
      D -= 2 * dx;
    }
    
    D += 2 * dy;
  }
}

function linePortrait(x0, y0, x1, y1) {
  if (y0 > y1) {
    [x0, x1] = [x1, x0];
    [y0, y1] = [y1, y0];
  }
  
  const dx = Math.abs(x1 - x0);
  const dy = y1 - y0;
  const xi = x0 > x1 ? -1 : 1;
  
  let D = 2 * dx - dy;  
  let x = x0;

  for (let y = y0; y <= y1; ++y) {
    paintPixel(x, y);
    
    if (D > 0) {
      x += xi;
      D -= 2 * dy;
    }
    
    D += 2 * dx;
  }
}
body {
  margin: 0;
  font-size: 0;
}

#canvas {
  width: 100%;
  height: 100vh;
}
<canvas id="canvas"></canvas>

Вы также можете адаптировать этот алгоритм для работы с вашим подходом, если вам действительно нужно использовать <div> s.

0 голосов
/ 03 июня 2018

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

...