定时器是我们经常使用的一个异步函数,它的用处十分广泛,比如图片轮播、各种小的动画、延时操作等等;定时器函数只有两个setTimeout、setInterval,这两个工作原理相同,唯一的区别是:setTimeout只执行一次,setInterval循环执行;通过以下实例看看对定时器原理掌握程度:
定时器3个实例
首先声明这三个实例输出皆不同,先思考输出结果,以及为何不同
实例一:
console.log(‘test1‘) for(var i=0;i<10;i++){ setTimeout(()=>{console.log(i)},1000); } console.log(‘test2‘)
实例二:
console.log(‘test1‘)for(let i=0;i<10;i++){
setTimeout(()=>{console.log(i)},1000); }
console.log(‘test2‘)
实例三
console.log(‘test1‘) for(let i=0;i<10;i++){ setTimeout(()=>{console.log(i)},1000*i); } console.log(‘test2‘)
结果如下:
实例一:‘test1‘ --> ‘test2‘ --> 同时输出十个10
实例二:‘test1‘ --> ‘test2‘ --> 同时输出0-9数字
实例三:‘test1‘ --> ‘test2‘ --> 每哥1s输出一个数字,数字从0-9
至于原因等会再讲,首先要先明白定时器的工作原理,而定时器的原理正是javascript事件循环模型的体现;
javascript运行机制:Event Loop
必须明确一点:javascript是单线程,同一时间只能做一件事;
单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。如果前一个任务耗时很长,后一个任务就不得不一直等着。
所谓单线程,是指在JS引擎中负责解释和执行JavaScript代码的线程只有一个。不妨叫它主线程。但是实际上还存在其他的线程。例如:处理AJAX请求的线程、处理DOM事件的线程、定时器线程、读写文件的线程(例如在Node.js中)等等。这些线程可能存在于JS引擎之内,也可能存在于JS引擎之外,在此我们不做区分。不妨叫它们工作线程。
如果排队是因为计算量大,CPU忙不过来,倒也算了,但是很多时候CPU是闲着的,因为IO设备(输入输出设备)很慢(比如Ajax操作从网络读取数据),不得不等着结果出来,再往下执行。
JavaScript语言的设计者意识到,这时主线程完全可以不管IO设备,挂起处于等待中的任务,先运行排在后面的任务。等到IO设备返回了结果,再回过头,把挂起的任务继续执行下去。于是,所有任务可以分成两种,一种是同步任务(synchronous),另一种是异步任务(asynchronous)。同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;异步任务指的是,不进入主线程、而进入"任务队列"(task queue)的任务,只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。
具体来说,异步执行的运行机制如下(以ajax为例):
解答上述实例
参考:(优质的文档能够准确,快速地理解掌握知识点;感谢以下文档)
[1] javascript: 彻底理解同步、异步、事件循环(Event Loop)
[2] javascript 运行机制详解:在谈Event Loop