如何防止IE11和Microsoft Edge积极地限制事件?

Joh*_*isz 11 javascript microsoft-edge

背景

我有一个可以通过监听mousemove事件然后使用相应transform: translate3d(...)地移动屏幕的pannable应用程序窗口.它是一个大型应用程序,并且有相当多的UI工作可以促进此功能.这是MCVE,其中真正的工作负载被虚拟for循环模拟:

var container = document.getElementById("container");
var contents = document.getElementById("contents");
var input = document.getElementById("iterations");

var posX = 50;
var posY = 50;
var previousX = null;
var previousY = null;

var mousedownHandler = function (e) {
    window.onmousemove = globalMousemoveHandler;
    window.onmouseup = globalMouseupHandler;
    previousX = e.clientX;
    previousY = e.clientY;
}

var globalMousemoveHandler = function (e) {
    var now = Date.now();
    for (var i = 0, n = parseInt(input.value); i < n; i++);
    var elapsed = Date.now() - now;

    posX += e.clientX - previousX;
    posY += e.clientY - previousY;
    previousX = e.clientX;
    previousY = e.clientY;
    contents.style.transform = "translate3d(" + posX + "px, " + posY + "px, 0)";
    contents.innerText = elapsed + "ms";
}

var globalMouseupHandler = function (e) {
    window.onmousemove = null;
    window.onmouseup = null;
    previousX = null;
    previousY = null;
}

container.onmousedown = mousedownHandler;
contents.style.transform = "translate3d(" + posX + "px, " + posY + "px, 0)";
Run Code Online (Sandbox Code Playgroud)
#container {
  height: 180px;
  width: 600px;
  background-color: #ccc;
  overflow: hidden;
  cursor: -webkit-grab;
  cursor: -moz-grab;
  cursor: grab;
  -moz-user-select: none;
  -ms-user-select: none;
  -webkit-user-select: none;
  user-select: none;
}

#container:active {
  cursor: move;
  cursor: -webkit-grabbing;
  cursor: -moz-grabbing;
  cursor: grabbing;
}
Run Code Online (Sandbox Code Playgroud)
<label>Iterations: <input id="iterations" type="number" value="20000000" step="5000000" /></label>

<div id="container">
    <div id="contents">
        Pannable container contents...
    </div>
</div>
Run Code Online (Sandbox Code Playgroud)

JSFiddle示例具有更大的拖动区域

请按住并拖动示例.

这个基本的片段for每次mousemove触发都会运行一个虚拟循环,循环完成所需的持续时间会显示在可拖动的容器中.这需要证明下面的问题.您可能需要调整迭代次数,以便循环运行时间超过10ms,但不会太长.

问题

此代码段在Google Chrome中尽可能快地运行,没有任何问题.在Firefox中未经测试.

但是,在Microsoft Edge (也可能是IE11)中,如果globalMousemoveHandler运行时间超过10毫秒,浏览器会开始重新限制事件,使其频繁发生火灾,并消除平移进度.

同样奇怪的是,for循环实际上在Microsoft Edge中运行速度比在Chrome中快得多(几乎快50%),但事件的发生频率仍然得多.

当从上述浏览器中查看时,在上面的片段中可以观察到这一点.现在我理解了这个功能背后的理论需求,但它使我的应用程序在这些浏览器上无法使用 - 我也不太明白在16ms以下限制的重点是什么(我在60 FPS帧预算之下),但现在除了问题之外(虽然我很高兴听到一些关于此的细节).

我怎样才能防止这种情况发生?

Kei*_*ith 4

这是使用requestAnimationFrame的示例。

var container = document.getElementById("container");
var contents = document.getElementById("contents");
var input = document.getElementById("iterations");

var posX = 50;
var posY = 50;
var previousX = null;
var previousY = null;

var mousedownHandler = function (e) {
    window.onmousemove = globalMousemoveHandler;
    window.onmouseup = globalMouseupHandler;
    previousX = e.clientX;
    previousY = e.clientY;
}

var globalMousemoveHandler = function (e) {
    posX += e.clientX - previousX;
    posY += e.clientY - previousY;
    previousX = e.clientX;
    previousY = e.clientY;
  
    window.requestAnimationFrame(function () {        
      var now = Date.now();
      for (var i = 0, n = parseInt(input.value); i < n; i++);
      var elapsed = Date.now() - now;

      contents.style.transform = "translate3d(" + posX + "px, " + posY + "px, 0)";
      contents.innerText = elapsed + "ms";
    });
}

var globalMouseupHandler = function (e) {
    window.onmousemove = null;
    window.onmouseup = null;
    previousX = null;
    previousY = null;
}

container.onmousedown = mousedownHandler;
contents.style.transform = "translate3d(" + posX + "px, " + posY + "px, 0)";
Run Code Online (Sandbox Code Playgroud)
#container {
  height: 180px;
  width: 600px;
  background-color: #ccc;
  overflow: hidden;
  cursor: -webkit-grab;
  cursor: -moz-grab;
  cursor: grab;
  -moz-user-select: none;
  -ms-user-select: none;
  -webkit-user-select: none;
  user-select: none;
}

#container:active {
  cursor: move;
  cursor: -webkit-grabbing;
  cursor: -moz-grabbing;
  cursor: grabbing;
}
Run Code Online (Sandbox Code Playgroud)
<label>Iterations: <input id="iterations" type="number" value="20000000" step="5000000" /></label>

<div id="container">
    <div id="contents">
        Pannable container contents...
    </div>
</div>
Run Code Online (Sandbox Code Playgroud)

这可以阻止繁重的工作阻塞处理程序功能,从而有效地防止问题发生,但代价是增加了 16 毫秒的延迟。

  • 好的完成.. :) `(为什么我没有考虑这个...)` 有时,问题只需要有人从另一个角度来看待它们。或者有时候,第二天它就会来找你。:) (2认同)