前言:关于最近面试遇到的setTimeout与setInterval相关面试题,网上搜索相关资料,进行学习总结。javascript
一、setTimeout与setInterval的区别?
java
setTimeout()方法用来指定某个函数或字符串在指定的毫秒数以后执行。它返回一个整数,表示定时器的编号,这个值能够传递给clearTimeout()用于取消这个函数的执行。面试
setInterval的用法与setTimeout彻底一致,区别仅仅在于setInterval指定某个任务每隔一段时间就执行一次,也就是无限次的定时执行。promise
setTimeout和setInterval函数,都返回一个表示计数器编号的整数值,将该整数传入clearTimeout和clearInterval函数,就能够取消对应的定时器。异步
二、看代码,写结果
函数
for (var i = 0; i < 5; i++) { setTimeout(function (){ console.log(i); },1000); }
结果:5,5,5,5,5学习
setTimeout是异步执行的,1000毫秒后向任务队列里添加一个任务,只有主线上的所有执行完才会执行任务队列里的任务,因此当主线程for循环执行完以后i的值为5,这个时候再去任务队列中执行任务,i所有为5;每次for循环的时候setTimeout都会执行,可是里面的function不会执行,所以放了5次,1000毫秒后所有执行完任务队列中的函数,因此输出五个5.spa
同时,i是var定义的,不属于for循环体,属于全局global。等for循环结束,i已经等于5了,这个时候执行回调函数,里面console.log(i)的i向上找做用域,只能找到全局下的i,即5.因此输出都是5.线程
三、如何解决上述问题,变成0,1,2,3,4code
a、当即执行函数
这样console.log(i)中的i就保存在每一次循环生成的当即执行函数中对的做用域里了。
for (var i = 0; i < 5; i++) { (function(i){ //马上执行函数 setTimeout(function (){ console.log(i); },1000); })(i); }
b、let做为代码块做用域,因此每一次 for 循环,console.log(i); 都引用到 for 代码块做用域下的i,由于这样被引用,因此 for 循环结束后,这些做用域在 setTimeout 未执行前都不会被释放。
for (let i = 0; i < 5; i++) { //let 代替 var setTimeout(function (){ console.log(i); },1000); }
四、setTimeout的做用是将代码推迟到指定时间执行,若是指定时间为0,即setTimeout(f,0),那么会马上执行吗?
不会。必须等当前脚本的同步任务和队列任务中全部事件执行完,才会执行setTimeout指定任务,将第二参数设置为0,目的是以前全部任务执行完后就当即执行,尽量早得执行指定任务
五、看代码,写结果
console.log("script start"); setTimeout(function(){ console.log("setTimeout"); },0); Promise.resolve().then(function(){ console.log("promise1"); }).then(function(){ console.log("promise2"); }); console.log("script end");
结果:
script start
script end
promise1
promise2
setTimeout
setTimeout和Promise调用都是异步任务,都是经过任务队列进行管理调度。分为宏任务队列和微任务队列,能够看出Promise比setTimeout()先执行。由于Promise定义以后便会当即执行,其后的.then()是异步里面的微任务。而setTimeout()是异步的宏任务。
从script(总体代码)开始第一次循环,全局上下文进入函数调用栈(栈底),若是有可执行代码就进行正常的入栈出栈,若是有上面提到的setTimeout和Promise,就将任务分发到各自队列,直到调用栈清空(只剩全局),而后执行全部的微任务队列(Promise队列),这就是第一次循环。当全部可执行的微任务执行完毕以后,循环再次从宏任务(setTimeout队列)开始执行入栈出栈任务分发等,执行完毕,而后再执行全部的微任务,第二次循环结束。。。这样一直循环下去,直到再也没有可执行的任务。这就是JS的循环机制。
console.log('打印'+1); setTimeout(function(){ console.log('打印'+2); }) new Promise(function(resolve,reject){ console.log('打印'+3); }).then( console.log('打印'+4));; console.log('打印'+10); new Promise(function(resolve,reject){ setTimeout(function () { console.log('打印'+5); }); }).then( console.log('打印'+6)); setTimeout(function(){ new Promise(function(resolve,reject){ console.log('打印'+7); }); })
打印1
打印3
打印4
打印10
打印6
打印2
打印5
打印7
console.log('打印'+1); setTimeout(function(){ console.log('打印'+2); }) new Promise(function(resolve){ console.log('打印'+3); resolve(); }).then(function(){ console.log(4); } ); console.log('打印'+10); new Promise(function(resolve){ setTimeout(function () { console.log('打印'+5); }); resolve(); }).then(function(){ console.log('打印'+6)}); setTimeout(function(){ new Promise(function(resolve){ console.log('打印'+7); }); })
打印1打印3打印10 4打印6打印2打印5打印7