setTimeout()函数

447 阅读3分钟

setTimeout()函数

setTimeout的定义

1.setTimeout函数是JavaScript语言内置提供的一个全局函数,作用类似于定时器,指定一个函数和一个时长,等这个时长过后调用函数。

  • setTimeout函数参数主要有两个,指定函数func,指定时长time,单位毫秒
    setTimeout(function(){ alert("Hello"); }, 3000);  //三秒之后执行函数
    setTimeout(alertFunc, 3000);  //三秒之后调用alertFunc函数
    function alertFunc() {  
     alert("Hello!");
    }```
    
  • 返回一个id值,用于标识此定时器,该id可以传递给clearTimeout()方法来取消执行
    • 在setTimeout()里面的函数执行之前可以使用cleaTimeout()方法阻止setTimeout()里面的函数执行。

setTimeout与this

1.setTimeout()调用的代码运行在与所在函数完全分离的执行环境上(因为直接调用该方法时,隐藏了setTimeout的对象,而这个对象就是JavaScript的全局对象)。全局对象与JavaScript的运行环境有关。(如浏览器环境中,全局对象为window对象)

2.在JavaScript中,函数内部的this指针指向调用当前函数的对象,全局作用域中的this指针指向全局对象。 而在setTimeout的回调函数中,该this指针始终指向window对象。

3.解决方法:

  • 使用局部变量,将this赋值给另一个变量:
let obj = {
    name:"hello",
    getA:function(){
        var _this=this;
        setTimeout(function(){
            console.log("hi,my name is"+_this.name;
        },time);
    }
}
obj.getA;
  • ES6语法,使用箭头函数(箭头函数中的this总是指向函数定义时的对象)
name:"Tom"
setTimeout(() => {
      console.log("Hi, my name is "+this.name);
   }, time);
  • bind函数

bind()方法是在Function.prototype上的一个方法,当被绑定函数执行时,bind方法创建一个新函数,并将第一个参数作为新函数运行时的this

let obj = {
    name:"hello",
    getA:function(){
        setTimeout(function(){
            console.log("hi,my name is"+this.name;
        }.bind(this),time);
    }
}
obj.getA;

循环中setTimeout()函数的输出问题

1.在for循环中使用var声明的变量是全局变量,当for循环执行完毕时,i为5,然后在等1s后调用setTimeout函数,输出的i就是全局作用域中的i,即是5。

for(var i=0;i<6;i++){
    setTimeout(()=>{
        console.log(i);
        },1000);
}

2.解决方法:

  • 使用let关键字
for(let i=0;i<6;i++){
    setTimeout(()=>{
        console.log(i);
        },1000);
}      //输出0 1 2 3 4 5
  • 使用闭包
for(var i=0;i<6;i++){
   (function(j){
    setTimeout(()=>{
        console.log(j);
        },1000);
    })(i);
}     //输出0 1 2 3 4 5

setTimeout、promise、console.log的执行顺序

1.JavaScript在浏览器下的执行模式

  • JavaScript是一个单线程语言,即是按照语句的执行顺序执行的,而异步明显不能与单线程共存。所以浏览器为了实现异步就采用了事件循环机制和任务队列。
    • 任务队列保存JavaScript未来需要执行的任务。
    • 事件循环是指浏览器会不停的从任务队列中去取任务执行,但只有当前任务执行完成后才会继续从任务队列中取任务去执行。
    • 这种事件循环机制,就说明setTimeout并不是精确的在某个时间后执行回调函数,而是在一段时间后将代码放到任务队列的末尾。如果时间设置为0,就表示的是立即插入任务队列,而不是立即就执行,必须等待任务队列中排在这个任务前面的任务执行完之后才会执行该任务。
    setTimeout(function(){
        console.log(2);
      },0);
      console.log(1);
      //输出顺序 1 2
    

2.setTimeout与promise执行顺序

执行顺序:Promise——>其后的.then()——>setTimeout(异步) ,即是Promise定义之后便会立即执行,其后的.then()是异步里面的微任务。 而setTimeout()是异步的宏任务。

setTimeout(function () {
  console.log('定时器开始啦')
});
new Promise(function (resolve) {
  console.log('马上执行for循环啦');
  for (var i = 0; i < 10000; i++) {
    i == 99 && resolve();
  }
}).then(function () {
  console.log('执行then函数啦')
});
console.log('代码执行结束');
//输出:马上执行for循环啦  代码执行结束  执行then函数啦  定时器开始啦