# 18、Js中的定时器与异步编程
# setTimeout(fn,interval)
设定一个定时器,到达指定时间之后执行对应的方法(执行一次就结束了)。
# setInterval(fn,interval)
setInterval
设置一个定时器,每间隔多少时间执行一次fn
,直到定时器清除为止(执行很多次)
interval
:代表的是每隔多久就重新执行一次回调函数,fn
执行的时间也计算在内了,如果fn
执行时间超过了interval
,那么下一次fn
会在本次fn
执行完成之后再执行。
# 两个定时器的区别
TIP
共同点: 设置定时器时都会有一个返回值,代表当前是在浏览器中设置的第几个定时器(返回的是定时器的序号,不管是setTimeout还是setInterval,)只要遇到这两个其中一个,就算一个新的定时器,定时器的序号就会加1,即使清除了设置的定时器,也不会重新计算序号。
不同点: setTimeout是隔一段时间之后执行一次函数 setInterval是每隔一段时间之后都执行一次函数;
清除定时器: 用clearTimeout来清除setTimeout设置的定时器,传入的参数为定时器的序号 用clearInterval来清除setInterval设置的定时器,传入的参数为定时器的序号;
# setInterval不准的问题
由于
setInterval
是把回调函数的执行时间计算在interval
内的,如果回调函数的执行时间过长,超出的了interval
时,就会出现间隔时间不准的问题。只能用setTimeout
来模拟setInterval
function mySetInterval(fn, delay, count){
function inner() {
if(count === undefined || count-- > 0){
setTimeout(inner,delay) // 写在这里表示函数的执行时间计算在 delay 内了,两次函数执行的间隔为 delay
try {
fn()
} catch ( err ) {
count = 0;
throw err.toString()
}
// setTimeout(inner,delay) 如果想要在执行间隔从上次函数执行结束算起,就写在这里
}
}
setTimeout(inner,delay)
}
# 为什么我们要手动清除定时器?
定时器也是一个函数,函数执行完成后,返回了一个基本数据类型值(定时器的序列号)。没有产生堆内存的话就会在空闲时间被销毁掉,但是为什么setTimeout不会自动销毁?
因为当创建一个定时器的时候,浏览器会同时开启一个监听者,当setTimeout执行完成后,监听者始终知道这个定时器的地址,所以不能销毁,我们要手动去清除定时器。我们手动清除的时候其实就是在切断定时器和监听者之间的联系;这样定时器就会被销毁掉;
# 定时器中的this问题
// 不管在哪执行,定时器函数中的this是window;
var obj={
fn:function(){
//this:obj
setTimeout(function(){
//=>this:window 不管在哪执行,定时器中的this是window
},1000);
//=>想让定时器函数中的this是obj,使用bind方法改变为obj
setTimeout(function(){
//=>this:obj
}.bind(this),1000);
//也可以用变量保存的方式来改变this
var _this=this;
setTimeout(function(){
//=>_this:obj
_this.name ='xxx';
},1000);
setTimeout(()=>{
//=>this:obj 箭头函数中的this继承宿主环境(上级作用域中)的this
},1000);
}
};
obj.fn();
# 同步编程和异步编程
JS是单线程的,当前的任务没有完成,下面的任务是不进行处理的(同步的)
# 同步编程
当前的事情没有完成,继续处理当前的事情,只有当前的事件完成了,才会去做下一件事情。(JS中大部分都是同步编程的)如for循环
# 异步编程
规划一件事情,但不是当前马上去执行这件事,需要一定时间之后再执行,不会等到时间到了,任务执行完了,才继续完成下面的任务。而是把它放到等待任务队列中,同时开始计算等待时间,继续执行主任务队列中的任务,只有主任务队列中的任务都完成了,再到等待任务队列当中,看哪个先到时间了,就先执行哪个。如果主任务队列中的任务没完成,不会去执行等待任务队列当中的任务;
# JS中的异步编程
在JS中的异步编程只有四种:
- 1、定时器都是异步编程的
- 2、所有的事件绑定都是异步编程、
- 3、Ajax读取数据的时候,我们一般都设置为异步编程
- 4、回调函数也是异步编程
定时器是有最小等待时间的,即使设置为0也不会马上执行,等待时间短的先执行;
# 同步异步编程的核心原理
JS中有两个任务队列(存放任务列表的空间就是任务队列)
- 1、主任务队列:同步执行任务;(从上到下执行)
- 2、等待任务队列:存放异步的任务;
原理:规划一件事情,但不是当前马上去执行这件事,需要一定时间之后再执行,不会等到时间到了,规划的任务执行完了,才继续完成下面的任务。而是把它放到等待任务队列中,开始计时,继续执行下面的操作,只有主任务队列中的任务都完成了,再到等待任务队列当中,看哪个先到时间了,就先执行哪个,如果都到时间了,那么就看哪个等待的时间短,就先执行哪一个。如果主任务队列中的任务没完成,不会去执行等待任务队列当中的任务;
# JS中动画实现的原理
# CSS3动画
TIP
在CSS3中提供了transition(过渡动画)/animation(帧动画) 优势: 性能好,实现起来简单,CSS能解决的动画绝对不用其他方式。 弊端: 不兼容大部分IE或者其他低版本浏览器(移动端的动画一般都是基于CSS3来完成的)
# JavaScript动画
在JS中实现动画常用的有:
1、使用定时器驱动动画, 2、使用requestAnimationFrame来完成的动画 而所谓的canvas动画基本上也是基于这两种方案完成的(canvas本身是绘图)
# Flash动画
非常早的动画处理方案,想要实现动画,需要把这部分制作成Flash影片,然后用Adobe Flash Player插件来播放;现在一些简单的DOM动画都告别了flash的时代,影片的播放也可以基于H5中的audio或者video完成;
# JS中基于定时器的动画运动的两种形式
TIP
1、限定步长,不限制运动时间; 2、限定运动的总时间,不限制每一步走的长度; 公式:
- time为定时器走一次的时间,zTime为运动总的时间
- 元素当前所在位置=(time/zTime*总路程+起始位置)
# 时间消耗测试
// 1、此方法只能测试运算时间在1毫秒以上的,
var startTime=new Date();
//需要测试消耗时间的代码
console.log(new Date()-startTime);
// 2、此方法可以测试运算时间在1毫秒以下的
console.time()
//需要测试消耗时间的代码
console.timeEnd()