JavaScript中setTimeout与setInterval

在写js代码过程中,超时调用 setTimeout 与 间隔调用 setInterval 方法会经常用到

setTimeout

基本使用

JavaScript是一个单线程的解释器,因此一段时间内只能执行一段代码,为了要控制执行的代码,就会有一个JavaScript的任务队列,这些任务会按照他们添加到队列的顺序执行。 setTimeout 的第二个参数会告诉JavaScript再过多长时间把当前任务添加进队列,如果队列是空的,那么添加 的代码会立即执行,如果队列不是空的,那么它要等前面的代码执行完了再执行。

//avoid!
setTimeout("alert('Hello world!') ", 1000);

//preferred
setTimeout(function() { 
    alert("Hello world!"); 
}, 1000);

setTimeout(() => {
    alert("haha");
}, 5000);

setTimeout(test, 10000);

function test() {
    alert('test');
}

以上代码可以帮助很好地理解JavaScript的任务队列这一功能,打开网页,我们等待10秒,会发现第一个 setTimeout 任务已经执行了,点击确认后,后续的弹窗都会出现,因为所有的 setTimeout 都已经到超时时间, 进入任务队列排队了。

几个注意点

this 的问题

当执行 setTimeout 中的回调函数时,它的执行环境(execution context)与调用 setTimeout 的执行环境不同,由此会引起函数调用与预期不符的问题,可以看MDN上的示例代码。

myArray = ['zero', 'one', 'two'];
myArray.myMethod = function (sProperty) {
  alert(arguments.length > 0 ? this[sProperty] : this);
};

myArray.myMethod(); // prints "zero,one,two"
myArray.myMethod(1); // prints "one"
setTimeout(myArray.myMethod, 1.0*1000); // prints "[object Window]" after 1 second
setTimeout(myArray.myMethod, 1.5*1000, '1'); // prints "undefined" after 1.5 seconds

可以发现,上述两部分代码运行结果不一致,因为 setTimeout 在调用myArray.myMethod 时没有设置它的 this, 所以这时候 this 就默认是 window,解决上述问题有两种方法,第一种是再包一层方法,第二种是直接用 bind

setTimeout(function(){myArray.myMethod()}, 2.0*1000); // prints "zero,one,two" after 2 seconds
setTimeout(function(){myArray.myMethod('1')}, 2.5*1000); // prints "one" after 2.5 seconds
myArray = ['zero', 'one', 'two'];
myBoundMethod = (function (sProperty) {
    console.log(arguments.length > 0 ? this[sProperty] : this);
}).bind(myArray);

myBoundMethod(); // prints "zero,one,two" because 'this' is bound to myArray in the function
myBoundMethod(1); // prints "one"
setTimeout(myBoundMethod, 1.0*1000); // still prints "zero,one,two" after 1 second because of the binding
setTimeout(myBoundMethod, 1.5*1000, "1"); // prints "one" after 1.5 seconds

setInterval

setInterval 用法和setTimeout 很相似,这里列下基本代码实例。

var num = 0;
var max = 10;
var intervalId = null;

function incrementNumber() {
    num++;

    //if the max has been reached, cancel all pending executions
    if (num == max) {
        clearInterval(intervalId);
        console.log("Done");
    } else {
        console.log('not yet');
    }
}

intervalId = setInterval(incrementNumber, 500);

需要注意,在开发模式下很少使用真正的间歇调用,原因是后一个间歇调用可能会在前一个间歇调用结束之前启动,推荐使用超时调用代替。

var num = 0;
var max = 100;

function incrementNumber() {
    num++;

    //if the max has not been reached, set another timeout
    if (num < max) {
        setTimeout(incrementNumber, 500);
    } else {
        var num = 0;
        var max = 10;
        
        function incrementNumber() {
            num++;
        
            //if the max has not been reached, set another timeout
            if (num < max) {
            	console.log('not yet');
                setTimeout(incrementNumber, 500);
            } else {
                console.log('not yet');
            }
        }
        
        setTimeout(incrementNumber, 500);
    }
}

setTimeout(incrementNumber, 500);

参考

JavaScript高级程序设计(第三版)
WindowOrWorkerGlobalScope.setTimeout()
Function.prototype.bind()
this

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值