【发布时间】:2016-06-25 02:06:33
【问题描述】:
为什么这对我很重要
我有一个网站,我需要运行一个倒数计时器,以向人们显示他们还剩下多少时间来完成一项操作。
此计时器将运行数天,并且可能只是使用 MomentJS 从 MomentJS 的 to() 函数中说出类似“4 天内”的内容。
但是,当我们还剩一个小时时,我将切换到按分钟倒计时的计时器,最终当分钟数足够低时,我将使用秒计时器。当我们进入最后几分钟时,我什至会显示毫秒。
问题
几乎有两种主要技术可以为倒数计时器设置动画。
setInterval()requestAnimationFrame()
嗯,我马上注意到requestAnimationFrame() 方法看起来更加流畅,效果很好——尤其是在我显示毫秒时。但是没过多久,我发现我可怜的电脑开始有点发热。所有这些“动画”都对我的 CPU 造成了相当大的负担。我尝试使用 CPU 监视器,并环顾四周,看看这会给我的 CPU 带来多少负载,但总的来说,我真的找不到一个工具可以清楚地显示我的小倒计时计时器是哪种 CPU 负载使用。
所以,我决定找到一种方法来限制 FPS,看看这是否会减少我的问题。是的,确实如此。如果您将setTimeout() 与requestAnimationFrame() 结合使用,您可以在调用下一个函数之前设置等待时间。
如果您使用的是setTimeout(),这就提出了一个问题——为什么不直接使用setInterval() 而忘记requestAnimationFrame() 为您提供的额外优化?
我环顾四周,发现了另一种方法,它只是检查自上次requestAnimationFrame() 调用您的函数以来是否经过了正确的间隔时间。我对这段代码的工作方式进行了一些优化,最终得到了我在下面尝试测量的两个函数之一。
最后,我真的很想有一个更清晰的方法来衡量这个 - 因为我的 mac 上的活动监视器几乎不是提供准确读数的可靠工具 - 我找不到一种方法来衡量我正在运行的代码。
Chrome 有更多工具、分析器和时间线 - 它们都非常有用,但它们没有提供我正在寻找的指标 - CPU 负载。
代码:
这里有四个代码 sn-ps,它们的作用完全相同——它们都使用:
- MomentJS
- CountdownJS
- jQuery
代码是 100% 相同的,唯一的区别是我如何限制动画的 FPS。
我想找到一种方法来衡量(尽可能精确地)这四个函数在它们占用的 CPU 负载方面的差异。然后我想更改 FPS 以查看是否可以为我的应用程序找到可接受的负载,然后我可以找到最佳点 - 在不同的计时器阶段,正确的 FPS 数量。
技巧 1 - setTimeout()
var now = moment(); // new Date().getTime();
var then = moment().add(60, 'seconds'); // new Date(now + 60 * 1000);
$(".now").text(moment(now).format('h:mm:ss a'));
$(".then").text(moment(then).format('h:mm:ss a'));
$(".duration").text(moment(now).to(then));
(function timerLoop() {
setTimeout(function(){
$(".difference").text(moment().to(then));
$(".countdown").text(countdown(then, null, countdown.YEARS | countdown.MONTHS | countdown.DAYS | countdown.HOURS | countdown.MINUTES | countdown.SECONDS | countdown.MILLISECONDS).toString());
requestAnimationFrame(timerLoop);
}, 1000/30);
})();
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.13.0/moment.min.js" type="text/javascript"></script>
<script src="https://cdn.rawgit.com/mckamey/countdownjs/master/countdown.min.js" type="text/javascript"></script>
<script src="https://code.jquery.com/jquery-3.0.0.min.js" type="text/javascript"></script>
<div>
The time is now: <span class="now"></span>, a timer will go off <span class="duration"></span> at <span class="then"></span>
</div>
<div>The timer is set to go off <span class="difference"></span></div>
<div class="countdown"></div>
技术 2 - 间隔之间的增量
var now = moment(); // new Date().getTime();
var then = moment().add(60, 'seconds'); // new Date(now + 60 * 1000);
$(".now").text(moment(now).format('h:mm:ss a'));
$(".then").text(moment(then).format('h:mm:ss a'));
$(".duration").text(moment(now).to(then));
var fps = 30;
var interval = 1000/fps;
var performanceTime = performance.now();
var performanceDelta;
(function updateCountdown(time) {
performanceDelta = time - performanceTime;
if (performanceDelta > interval) {
performanceTime = time - (performanceDelta % interval);
$(".difference").text(moment().to(then));
$(".countdown").text(countdown(then, null, countdown.YEARS | countdown.MONTHS | countdown.DAYS | countdown.HOURS | countdown.MINUTES | countdown.SECONDS | countdown.MILLISECONDS).toString());
}
requestAnimationFrame(updateCountdown);
})();
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.13.0/moment.min.js" type="text/javascript"></script>
<script src="https://cdn.rawgit.com/mckamey/countdownjs/master/countdown.min.js" type="text/javascript"></script>
<script src="https://code.jquery.com/jquery-3.0.0.min.js" type="text/javascript"></script>
<div>
The time is now: <span class="now"></span>, a timer will go off <span class="duration"></span> at <span class="then"></span>
</div>
<div>The timer is set to go off <span class="difference"></span></div>
<div class="countdown"></div>
技巧 3 - setInterval()
var now = moment(); // new Date().getTime();
var then = moment().add(60, 'seconds'); // new Date(now + 60 * 1000);
$(".now").text(moment(now).format('h:mm:ss a'));
$(".then").text(moment(then).format('h:mm:ss a'));
$(".duration").text(moment(now).to(then));
var fps = 30;
var interval = 1000/fps;
setInterval(function updateCountdown() {
$(".difference").text(moment().to(then));
$(".countdown").text(countdown(then, null, countdown.YEARS | countdown.MONTHS | countdown.DAYS | countdown.HOURS | countdown.MINUTES | countdown.SECONDS | countdown.MILLISECONDS).toString());
}, interval);
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.13.0/moment.min.js" type="text/javascript"></script>
<script src="https://cdn.rawgit.com/mckamey/countdownjs/master/countdown.min.js" type="text/javascript"></script>
<script src="https://code.jquery.com/jquery-3.0.0.min.js" type="text/javascript"></script>
<div>
The time is now: <span class="now"></span>, a timer will go off <span class="duration"></span> at <span class="then"></span>
</div>
<div>The timer is set to go off <span class="difference"></span></div>
<div class="countdown"></div>
看到像这样完全不受限制的版本也会很有趣:
技巧 4 - 无油门
var now = moment(); // new Date().getTime();
var then = moment().add(60, 'seconds'); // new Date(now + 60 * 1000);
$(".now").text(moment(now).format('h:mm:ss a'));
$(".then").text(moment(then).format('h:mm:ss a'));
$(".duration").text(moment(now).to(then));
(function timerLoop() {
$(".difference").text(moment().to(then));
$(".countdown").text(countdown(then, null, countdown.YEARS | countdown.MONTHS | countdown.DAYS | countdown.HOURS | countdown.MINUTES | countdown.SECONDS | countdown.MILLISECONDS).toString());
requestAnimationFrame(timerLoop);
})();
// CountdownJS: http://countdownjs.org/
// MomentJS: http://momentjs.com/
// jQuery: https://jquery.com/
// Rawgit: http://rawgit.com/
// Light reading about the requestAnimationFrame pattern:
// http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/
// https://css-tricks.com/using-requestanimationframe/
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.13.0/moment.min.js" type="text/javascript"></script>
<script src="https://cdn.rawgit.com/mckamey/countdownjs/master/countdown.min.js" type="text/javascript"></script>
<script src="https://code.jquery.com/jquery-3.0.0.min.js" type="text/javascript"></script>
<div>
The time is now: <span class="now"></span>, a timer will go off <span class="duration"></span> at <span class="then"></span>
</div>
<div>The timer is set to go off <span class="difference"></span></div>
<div class="countdown"></div>
简而言之:如何衡量四个类似 javascript 函数之间的 CPU 负载差异?
是否有人已经知道其中哪一个会更性能? (我知道这不是真的一个词)
【问题讨论】:
标签: javascript performance settimeout setinterval requestanimationframe