setTimeout与setInterval

前言:关于最近面试遇到的setTimeout与setInterval相关面试题,网上搜索相关资料,进行学习总结。

1、setTimeout与setInterval的区别?

 

setTimeout()方法用来指定某个函数或字符串在指定的毫秒数之后执行。它返回一个整数,表示定时器的编号,这个值可以传递给clearTimeout()用于取消这个函数的执行。

setInterval的用法与setTimeout完全一致,区别仅仅在于setInterval指定某个任务每隔一段时间就执行一次,也就是无限次的定时执行。

setTimeout和setInterval函数,都返回一个表示计数器编号的整数值,将该整数传入clearTimeout和clearInterval函数,就可以取消对应的定时器。

 

2、看代码,写结果

 

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.

同时,i是var定义的,不属于for循环体,属于全局global。等for循环结束,i已经等于5了,这个时候执行回调函数,里面console.log(i)的i向上找作用域,只能找到全局下的i,即5.所以输出都是5.

 

3、如何解决上述问题,变成0,1,2,3,4

 

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); 
}

 

4、setTimeout的作用是将代码推迟到指定时间执行,如果指定时间为0,即setTimeout(f,0),那么会立刻执行吗?

不会。必须等当前脚本的同步任务和队列任务中所有事件执行完,才会执行setTimeout指定任务,将第二参数设置为0,目的是之前所有任务执行完后就立即执行,尽可能早得执行指定任务

 

5、看代码,写结果

 

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

 

转载于:https://www.cnblogs.com/zsj-Blog/p/10449006.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值