# 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()
上次更新: 7/1/2020, 7:00:44 PM