我想要实现的是检测屏幕上出现某种变化的精确时间(主要针对Google Chrome)。例如,我使用
基本上,正如我所想象的那样,rAF应该在大约0-17毫秒内执行其中的所有内容(每当下一个帧出现在我的标准60 Hz屏幕上时)。此外,时间戳参数应该给出此执行的时间值(该值基于与performance.now()相同的DOMHighResTimeStamp度量)。
现在,这里是我进行的许多测试之一:https://jsfiddle.net/gasparl/k5nx7zvh/31/
我在Chrome浏览器中看到的是:rAF函数始终在大约0-3毫秒内执行(从它之前立即进行performance.now()计时),最奇妙的是,rAF时间戳与我在rAF内部使用performance.now()获得的时间戳完全不同,通常比rAF之前调用的performance.now()早约0-17毫秒(但有时会晚约0-1毫秒)。
以下是一个典型的示例:
在Firefox和IE中,情况不同。在Firefox中,“before vs. RAF callback start”的时间要么是大约1-3毫秒,要么是大约16-17毫秒。而“before vs. RAF stamp”总是正数,通常在0-3毫秒左右,但有时会在3-17毫秒之间。在IE中,这两个差异几乎总是在15-18毫秒(正数)左右。这些差异在不同的PC上基本相同。然而,当我在手机的Chrome上运行它时,只有那时它似乎是正确的:“before vs. RAF stamp”随机在0-17之间,“RAF callback start”总是在几毫秒后。
更多背景信息:这是一项在线响应时间实验,用户使用自己的PC(但我通常限制浏览器为Chrome,因此只有Chrome浏览器对我很重要)。我反复显示各种项目,并将响应时间测量为“从元素显示时(当人们看到它时)到按下键的那一刻”,并根据特定项目记录的响应时间计算平均值,然后检查某些项目类型之间的差异。这也意味着,如果记录的时间总是朝一个方向偏斜一点(例如始终比元素实际出现早3毫秒),这并不太重要,只要这种偏斜对于每个显示都是一致的,因为只有差异真正重要。1-2毫秒的精度是理想的,但任何减少随机“刷新率噪声”(0-17毫秒)的东西都会很好。
我还尝试过
使用HTML:
$("xelement").show();
来显示一个项目或使用$("#xelement").text("sth new");
进行更改,然后我想知道在给定屏幕重绘时,变化出现在用户屏幕上时performance.now()的确切值。因此,我完全接受任何解决方案-下面我只是主要参考requestAnimationFrame(rAF),因为它是旨在帮助实现这一点的函数,但似乎没有成功;请见下文。基本上,正如我所想象的那样,rAF应该在大约0-17毫秒内执行其中的所有内容(每当下一个帧出现在我的标准60 Hz屏幕上时)。此外,时间戳参数应该给出此执行的时间值(该值基于与performance.now()相同的DOMHighResTimeStamp度量)。
现在,这里是我进行的许多测试之一:https://jsfiddle.net/gasparl/k5nx7zvh/31/
function item_display() {
var before = performance.now();
requestAnimationFrame(function(timest){
var r_start = performance.now();
var r_ts = timest;
console.log("before:", before);
console.log("RAF callback start:", r_start);
console.log("RAF stamp:", r_ts);
console.log("before vs. RAF callback start:", r_start - before);
console.log("before vs. RAF stamp:", r_ts - before);
console.log("")
});
}
setInterval(item_display, Math.floor(Math.random() * (1000 - 500 + 1)) + 500);
我在Chrome浏览器中看到的是:rAF函数始终在大约0-3毫秒内执行(从它之前立即进行performance.now()计时),最奇妙的是,rAF时间戳与我在rAF内部使用performance.now()获得的时间戳完全不同,通常比rAF之前调用的performance.now()早约0-17毫秒(但有时会晚约0-1毫秒)。
以下是一个典型的示例:
before: 409265.00000001397
RAF callback start: 409266.30000001758
RAF stamp: 409260.832
before vs. RAF callback start: 1.30000000353902
before vs. RAF stamp: -4.168000013974961
在Firefox和IE中,情况不同。在Firefox中,“before vs. RAF callback start”的时间要么是大约1-3毫秒,要么是大约16-17毫秒。而“before vs. RAF stamp”总是正数,通常在0-3毫秒左右,但有时会在3-17毫秒之间。在IE中,这两个差异几乎总是在15-18毫秒(正数)左右。这些差异在不同的PC上基本相同。然而,当我在手机的Chrome上运行它时,只有那时它似乎是正确的:“before vs. RAF stamp”随机在0-17之间,“RAF callback start”总是在几毫秒后。
更多背景信息:这是一项在线响应时间实验,用户使用自己的PC(但我通常限制浏览器为Chrome,因此只有Chrome浏览器对我很重要)。我反复显示各种项目,并将响应时间测量为“从元素显示时(当人们看到它时)到按下键的那一刻”,并根据特定项目记录的响应时间计算平均值,然后检查某些项目类型之间的差异。这也意味着,如果记录的时间总是朝一个方向偏斜一点(例如始终比元素实际出现早3毫秒),这并不太重要,只要这种偏斜对于每个显示都是一致的,因为只有差异真正重要。1-2毫秒的精度是理想的,但任何减少随机“刷新率噪声”(0-17毫秒)的东西都会很好。
我还尝试过
jQuery.show()
回调,但它没有考虑刷新率:https://jsfiddle.net/gasparl/k5nx7zvh/67/
var r_start;
function shown() {
r_start = performance.now();
}
function item_display() {
var before = performance.now();
$("#stim_id").show(complete = shown())
var after = performance.now();
var text = "before: " + before + "<br>callback RT: " + r_start + "<br>after: " + after + "<br>before vs. callback: " + (r_start - before) + "<br>before vs. after: " + (after - r_start)
console.log("")
console.log(text)
$("p").html(text);
setTimeout(function(){ $("#stim_id").hide(); }, 500);
}
setInterval(item_display, Math.floor(Math.random() * (1000 - 500 + 1)) + 800);
使用HTML:
<p><br><br><br><br><br></p>
<span id="stim_id">STIMULUS</span>
根据Kaiido的答案提供的解决方案,包括工作示例:
function monkeyPatchRequestPostAnimationFrame() {
const channel = new MessageChannel();
const callbacks = [];
let timestamp = 0;
let called = false;
channel.port2.onmessage = e => {
called = false;
const toCall = callbacks.slice();
callbacks.length = 0;
toCall.forEach(fn => {
try {
fn(timestamp);
} catch (e) {}
});
};
window.requestPostAnimationFrame = function(callback) {
if (typeof callback !== 'function') {
throw new TypeError('Argument 1 is not callable');
}
callbacks.push(callback);
if (!called) {
requestAnimationFrame((time) => {
timestamp = time;
channel.port1.postMessage('');
});
called = true;
}
};
}
if (typeof requestPostAnimationFrame !== 'function') {
monkeyPatchRequestPostAnimationFrame();
}
function chromeWorkaroundLoop() {
if (needed) {
requestAnimationFrame(chromeWorkaroundLoop);
}
}
// here is how I display items
// includes a 100 ms "warm-up"
function item_display() {
window.needed = true;
chromeWorkaroundLoop();
setTimeout(function() {
var before = performance.now();
$("#stim_id").text("Random new text: " + Math.round(Math.random()*1000) + ".");
$("#stim_id").show();
// I ask for display above, and get display time below
requestPostAnimationFrame(function() {
var rPAF_now = performance.now();
console.log("before vs. rPAF now:", rPAF_now - before);
console.log("");
needed = false;
});
}, 100);
}
// below is just running example instances of displaying stuff
function example_loop(count) {
$("#stim_id").hide();
setTimeout(function() {
item_display();
if (count > 1) {
example_loop(--count);
}
}, Math.floor(Math.random() * (1000 - 500 + 1)) + 500);
}
example_loop(10);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.3/jquery.min.js"></script>
<div id="stim_id">Any text</div>
编辑:根据实际测量,所有这些中,结果是唯一重要的是rAF循环。rPAF没有真正的影响。
有些浏览器可能也会稍微随机时间戳
。 - Jaromanda X