【问题标题】:Javascript keydown timingJavascript keydown 时间
【发布时间】:2014-10-27 10:10:40
【问题描述】:

我正在开发一个对时间非常敏感的应用程序,它使用按键进行用户输入。当我在这里谈论毫秒时,我继续尝试了这样的版本:

function start() {
  //stim.style.display = "block";
  rt_start = new Date().getTime();
  response_allowed = 1;
}

function end() {
  var t = rt_end - rt_start;
  //stim.style.display = "none";
  log.innerHTML = t;
  i++;
  if (i < iterations) {
    setTimeout('start();', 1000);
  }
}

var rt_start;
var rt_end;
var iterations = 100;
var i = 0;
var response_allowed = 0;
var stim;
var log;
$(document).ready(function() {
  document.onkeydown = function(e) {
    if (response_allowed == 1) {
      rt_end = new Date().getTime();
      response_allowed = 0;
      end();
    }
  };
  stim = document.getElementById('stim');
  log = document.getElementById('log');
  start();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="log"></div>
<img src="https://www.gravatar.com/avatar/cfefd93404e6b0eb3cde02b4b6df4e2b?s=128&d=identicon&r=PG&f=1" id="stim" />

而且它工作正常,通常是低于 5 毫秒的计时器(只需按住一个键)。但是一旦我修改代码以显示图像(取消注释这两行),这会减慢很多到大约 30 毫秒。

有人能告诉我为什么会出现这种情况以及如何避免这种额外的延迟吗?

谢谢

【问题讨论】:

  • 你能提供一个jsfiddle吗?
  • 旁注:几乎没有任何理由将字符串传递给setTimeout/setInterval,还有几个的原因。相反,传递对您要调用的函数的引用:setTimeout(start, 1000);
  • jsfiddle 由于 setTimeout 似乎不起作用?至少我不能让它早点工作,对不起。字符串的传递是由于我在原始脚本中传递多个函数/动作的方法,例如显示 div,更改其内容等。这些是链接在一起的各种操作。编辑:动作是高度可变的,所以没有办法为每个动作定义一个函数。
  • @KarstenSender:jsFiddle 可以使用 setTimeout (jsfiddle.net/gcvtaxfm),但我已经更新了您的问题,将您的代码转换为 Stack Snippet(我使用了您的 gravatar,而不是 test.png)。
  • FWIW,在上面的版本中,按住一个键会给我大约 23 毫秒范围内的值。 (按住一个键意味着我们正在等待 keyrepeat,不是吗?)

标签: javascript jquery timing onkeydown


【解决方案1】:

我建议在可用的情况下使用 DOMHighResTimeStamp(对于不提供 polyfill 的浏览器)。

这是一个高分辨率时间戳(设计时考虑到精确测量),可用于(例如)导航计时和 Web 性能 API(在 Mozilla 开发者网络中搜索这个,因为我不能分享超过两个单个帖子中的链接)。

获取 DOMHighResTimeStamp 的快速方法 - 就像使用 var ts = new Date().getTime(); 获取常规毫秒时间戳一样 - 是:

var ts = performance.now();

如上所述,请查看 MDN 上的 Web 性能 API。如果您的应用程序对时间非常敏感,这将非常有帮助。

编辑:

关于您的 sn-p,在我看来,如果您按住一个键,您将始终受限于 keydown 事件的分辨率(它连续触发,但不是每毫秒触发一次)。如果您使用文本编辑器(连续)按下字符键并检查该字符每秒写入的次数,您可以很容易地看到此行为。我猜,这是通过操作系统设置控制的。

您还受限于与 setTimeout/setInterval 相关的“漂移”。您会看到,setTimeout 会在 给定延迟 之后将 something 排队等待执行,但它不能保证及时执行。这是一个“尽力而为”的场景,如果浏览器忙于做某事,它会显着漂移。含义:如果您使用 setTimeout 在 1 秒后重新启用 response_allowed 变量,您可以预期它会在“大约”(但不完全是)1 秒后重新启用它。

【讨论】:

  • 您好,感谢您的回答。我已经测试了 performance.now(),但它似乎比 Date.now() 产生了更高的负载(请参阅jsperf.com/date-now-vs-new-date-gettime/34)。 setTimeout 的延迟在这里应该没有问题,因为我只在函数内开始计时——因此忽略了迭代之间的(或多或少)1000 毫秒。正如@TJCrowder 所提到的,更大的问题可能是keydown 事件中存在延迟。这已经(在某种程度上)通过一个名为 Keydrown (jeremyckahn.github.io/keydrown) 的小程序得到确认和修复。谢谢!
猜你喜欢
  • 2021-10-09
  • 1970-01-01
  • 2017-11-02
  • 2019-05-16
  • 1970-01-01
  • 1970-01-01
  • 2012-08-05
  • 1970-01-01
  • 2014-07-29
相关资源
最近更新 更多