在Web浏览器中触发事件的最大速率是多少?

时间:2018-06-03 00:51:12

标签: javascript html performance javascript-events mouseevent

我正在尝试解决我在一个简单的像素画家应用程序中遇到的一些性能问题。当按住鼠标并且正在悬停div时,该div应该改变其背景颜色。它做到了!问题是当快速移动鼠标时,沿着半定时器间隔跳过某些div。这向我提出了某种抽样问题。

我很想知道Web浏览器的最大事件发生频率是多少,以及是否在某些标准中指定(与ES6相关)。

感兴趣的人的情况: Grid With Intervals

3 个答案:

答案 0 :(得分:1)

更有可能的是,当下一个事件进入并且拖动你的cpu时,你的绘画代码仍在运行。您只需要在处理程序中缓存鼠标,然后将绘图工作与事件异步。合作多任务风格。

答案 1 :(得分:1)

使用<canvas>可以帮助您实现更顺畅的行为:

&#13;
&#13;
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);
}
&#13;
body {
  margin: 0;
  font-size: 0;
}

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

但是,要完全避免这些间隙,您必须从一个光标位置到下一个光标位置绘制一条线,而不是绘制一个像素&#34;像素&#34;。

我会使用Bresenham's line algorithm来计算连续事件之间的所有点。像这样:

&#13;
&#13;
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;
  }
}
&#13;
body {
  margin: 0;
  font-size: 0;
}

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

如果您确实需要使用<div>,您还可以调整该算法以使用您的方法。

答案 2 :(得分:0)

据我所知,没有任何标准可以解雇事件。正如我所经历的那样,取决于影响当前用户机器功率的诸多因素。

看,我在这个画布中绘制了两行点在固定的Y位置和当前的X位置。上面的一个像脚本一样频繁地更新,而另一个是用mouseMoved事件绘制的。正如您所看到的,结果几乎相同(即使MouseMove中的点有时更常见) dots frecuency comparison 事件处理程序所需的时间影响很大,事实上我让方法等待1秒然后绘制,结果是间隔5厘米的点以相同的速度移动鼠标。

因此,当cpu忙于事件处理程序时,它更有可能不参与新的事件触发器。我唯一的推荐是停止事件传播,因此它不消耗任何资源并返回false,因此浏览器不会执行任何默认行为。