JavaScript 是单线程语言,但它可以通过设置超时调用或间歇调用来调度代码在特定的时刻执行。 JavaScript 中的定时器函数包括 window
对象的超时调用方法 setTimeout()
和间歇调用方法 setInterval()
。
定时器函数接收一个函数参数和一个延迟或间隔的毫秒数参数,返回一个调用 ID。
调用定时器函数以后,定时器函数经过延迟以后将函数参数添加到任务队列中。如果任务队列是空的,那么函数参数立即执行;如果任务队列不为空,那么等到前面的任务执行完以后再执行函数参数。
可以通过将调用 ID 作为参数传入 clearTimeout()
或 clearInterval()
方法取消超时调用或间歇调用。
使用超时调用模拟间歇调用
在开发环境下很少使用真正的间歇调用,原因是后一个间歇调用可能会在前一个间歇调用结束之前启动,可以使用超时调用模拟间歇调用来避免这一点。
例如:
function doSomething () {
// 代码
}
var intervalId = setInterval(doSomething, 500);
使用超时调用模拟间歇调用:
function doSomething () {
// 代码
setTimeout(doSomething, 500);
}
var timeoutId = setTimeout(doSomething, 500);
函数参数的 this 指向
定义以下变量和函数:
var name = 'Nicholas';
function Person () {
this.name = 'Greg';
this.sayName = function () {
console.log(this.name);
};
this.sayNameLater = function () {
setTimeout(this.sayName, 500);
};
}
var person = new Person();
调用 person
对象的 sayName()
和 sayNameLater()
方法,结果为:
person.sayName(); // 'Greg'
person.sayNameLater(); // 'Nicholas'
可以看出,定时器函数的函数参数的内部上下文的 this
指向的是 window
对象而不是 person
对象。即:
setTimeout(this.sayName, 500); // this指向当前上下文
setTimeout(function () {
console.log(this.name); // this指向window对象
};
使用闭包使 this 指向正确的值
修改 sayNameLater()
方法:
this.sayNameLater = function () {
var that = this;
setTimeout(function () {
that.sayName();
}, 500);
};
调用sayNameLater()
方法结果为:
person.sayNameLater(); // 'Greg'
使用 bind 方法
修改 sayNameLater()
方法:
this.sayNameLater = function () {
setTimeout(this.sayName.bind(this), 500);
};
调用 sayNameLater()
方法结果为:
person.sayNameLater(); // 'Greg'
注:如果使用 call()
或 apply()
方法会导致函数参数立即执行而失去超时或间歇调用的效果。