这是我参与2022首次更文挑战的第14天,活动详情查看:2022首次更文挑战
介绍
相信看到标题大家就会想到定时器等等在网页开发中已经烂大街了,但是它就像打台球一样,越是感觉基础简单的东西,往往越是失误和问题也是最多的。本期我就来介绍四种“操控时间”方法,看看你真的会使用他们么。
setTimeout()
它是我们最常用的定时器方法,他在定时到一定周期后执行一个函数或指定的一段代码。
let timer = setTimeout(() => {
console.log("完成")
}, 1000)
它也可以被清除掉:
clearTimeout(timer)
我们经常见到优化防抖也依赖它们去完成实现:
function debounce(handler, delay) {
var handler = handler || null;
var delay = ~~delay || 1000;
var timer = null;
return function() {
clearTimeout(timer)
timer = setTimeout(function() {
handler.apply(this, arguments);
}.bind(this), delay)
}
}
而且,如果想在主进程执行完之后立即执行,我们可以把时间直接设置成0ms,完成某些需求的时候非常有用:
setTimeout(()=>{
console.log(2);
}, 0);
console.log(1);
setInterval()
与setTimeout相似,不过它可以在一定周期内不断的执行函数或指定的一段代码。
let timer = setInterval(() => {
console.log("完成+1")
}, 1000)
当然,它也可以被清除掉:
clearInterva(timer)
但要注意的是,setInterval的运行周期与setTimeout相比并不是那么的稳定,虽然它更像是无数个setTimeout,但它不完全是。它的周期会出现更多的时间误差,如果你想误差小一点,可以用递归+setTimeout的方式或者requestAnimationFrame去代替setInterval。
requestAnimationFrame()
它 是一个专门用来循环函数,尤其需要高效运行动画之时,众所周知,动画的平滑度直接取决于动画的帧速率,并以每秒帧数(fps)为单位进行测量。这个数字越高,动画看起来就越平滑。为了满足我们肉眼观察动画是否掉帧卡顿的必要条件是1000毫秒需要60帧(注意:屏幕刷新率60Hz),也就是1帧需要16.7毫秒,而setTimeout和setInterval受计算机本身性能影响非常厉害,每次的值很有可能不是16.7。而requestAnimationFrame做到了这点,让帧率相对的恒定起来,而且使用requestAnimationFrame可以节约内存。目前几乎所有的H5游戏引擎内置的刷新都使用了它。
接下来,看看他是如何使用的。
function step(delta) {
console.log(delta)
requestAnimationFrame(step.bind(this));
}
刚打印了下delta,可以每次执行两两之差基本都会维持在16.6左右。如果是在执行动画的话将会是非常的平滑了。
另外,我们经常在游戏中有什么隔一段时间生成敌人,可以利用它再配合时间戳来实现:
let startTime = new Date().getTime()
let endTime = new Date().getTime();
let duration = 800; // 间隔周期
function step(delta) {
requestAnimationFrame(step.bind(this))
render(delta) // 渲染
if (endTime - startTime > duration) {
createEnemy() //生成敌人
startTime = endTime // 重新记录时间
}
endTime = new Date().getTime();
}
我们可以用这个方法周期内控制画面终止等等操作,也是非常方便的。
当然,它也存在一个撤销的操作的能力:
let timer = requestAnimationFrame(step.bind(this))
cancelAnimationFrame(timer);
其实,其兼容性已经比较好了,但是考虑到ie10以下还有安卓4.4以下的用户,可以写一个兼容写法来自动向下降级成setTimeout。
window.requestAnimFrame = (function() {
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||
function(callback,element) {
return window.setTimeout(callback, 1000 / 60);
};
})();
sleep()
经常有面试的时候问如何让网页睡眠假死呢,毕竟js不是java没有这个内置的api。那么如何让web形成假死睡眠状态呢。其实也不难相出办法,因为js是单线程,所以我们可以用while不断循环去阻塞,网页的进行。到达某个时间点再激活它。
接下来,我们尝试实现下:
function sleep(time = 1) {
let startTime = new Date().getTime();
let nowTime = new Date().getTime();
while (startTime+time>nowTime) {
nowTime = new Date().getTime();
}
}
document.getElementById("btn").addEventListener("click", e => {
console.log("我要执行啦~",new Date())
sleep(2000)
console.log("我执行完啦~",new Date())
})
这时sleep下面的代码都将会阻塞不能执行,整个网页变成了假死睡眠状态,直到2000后再次激活,后面的代码才会相继执行。