一直困扰着我的事情是setTimeout()
Javascript 中的方法是多么不可预测。
根据我的经验,计时器在很多情况下都非常不准确。不准确,我的意思是实际延迟时间似乎或多或少有 250-500 毫秒的变化。虽然这不是很长的时间,但是当使用它来隐藏/显示 UI 元素时,时间会很明显。
是否有任何技巧可以确保setTimeout()
准确执行(无需求助于外部 API),或者这是一个失败的原因?
一直困扰着我的事情是setTimeout()
Javascript 中的方法是多么不可预测。
根据我的经验,计时器在很多情况下都非常不准确。不准确,我的意思是实际延迟时间似乎或多或少有 250-500 毫秒的变化。虽然这不是很长的时间,但是当使用它来隐藏/显示 UI 元素时,时间会很明显。
是否有任何技巧可以确保setTimeout()
准确执行(无需求助于外部 API),或者这是一个失败的原因?
是否有任何技巧可以确保
setTimeout()
准确执行(无需求助于外部 API),或者这是一个失败的原因?
没有也没有。你不会得到任何接近完美准确的计时器setTimeout()
- 浏览器没有为此设置。但是,您也不需要依赖它来计时。大多数动画库在几年前就发现了这一点:您使用 设置回调setTimeout()
,但根据 的值(new Date()).milliseconds
(或等效值)确定需要执行的操作。这使您可以在较新的浏览器中利用更可靠的计时器支持,同时在较旧的浏览器上仍能正常运行。
它还可以让您避免使用太多计时器!这很重要:每个计时器都是一个回调。每个回调都执行 JS 代码。当 JS 代码正在执行时,浏览器事件——包括其他回调——被延迟或丢弃。当回调完成时,额外的回调必须与其他浏览器事件竞争执行的机会。因此,一个处理该时间间隔内所有待处理任务的计时器将比两个具有重合时间间隔的计时器执行得更好,并且(对于短超时)比具有重叠超时的两个计时器更好!
总结:停止使用setTimeout()
实现“一个定时器/一个任务”的设计,并使用实时时钟来平滑UI动作。
.
参考;http://www.sitepoint.com/creating-accurate-timers-in-javascript/
这个网站在很大程度上拯救了我。
您可以使用系统时钟来补偿计时器的不准确性。如果您将计时函数作为一系列 setTimeout 调用运行 - 每个实例调用下一个 - 那么您需要做的就是确保它准确无误,并从下一次迭代中减去该差异:
var start = new Date().getTime(),
time = 0,
elapsed = '0.0';
function instance()
{
time += 100;
elapsed = Math.floor(time / 100) / 10;
if(Math.round(elapsed) == elapsed) { elapsed += '.0'; }
document.title = elapsed;
var diff = (new Date().getTime() - start) - time;
window.setTimeout(instance, (100 - diff));
}
window.setTimeout(instance, 100);
这种方法将最大限度地减少漂移并将不准确率降低 90% 以上。
解决了我的问题,希望有帮助
不久前我遇到了类似的问题,并提出了一种requestAnimationFrame
与 performance.now()结合使用的方法,该方法非常有效。
我现在能够使计时器精确到大约 12 位小数:
window.performance = window.performance || {};
performance.now = (function() {
return performance.now ||
performance.mozNow ||
performance.msNow ||
performance.oNow ||
performance.webkitNow ||
function() {
//Doh! Crap browser!
return new Date().getTime();
};
})();
如果您需要在给定的时间间隔内获得准确的回调,此要点可能会帮助您:
https://gist.github.com/1185904
function interval(duration, fn){
var _this = this
this.baseline = undefined
this.run = function(){
if(_this.baseline === undefined){
_this.baseline = new Date().getTime()
}
fn()
var end = new Date().getTime()
_this.baseline += duration
var nextTick = duration - (end - _this.baseline)
if(nextTick<0){
nextTick = 0
}
_this.timer = setTimeout(function(){
_this.run(end)
}, nextTick)
}
this.stop = function(){
clearTimeout(_this.timer)
}
}
shog9 的回答几乎就是我想说的,尽管我会添加以下关于 UI 动画/事件的内容:
如果你有一个盒子,它应该滑到屏幕上,向下扩展,然后淡入它的内容,不要试图让所有三个事件分开,延迟时间让它们一个接一个地触发 - 使用回调,所以一次第一个事件完成滑动它调用扩展器,一旦完成它调用推子。jQuery 可以轻松完成,我相信其他库也可以。