Javascript setInterval与setTimeout详解

Javascript setInterval与setTimeout详解


1. Javascript运行机制

Javascript是单线程语言,同步任务在主线程队列中按顺序依次执行,这就意味着后一个任务必须等待前一个任务执行完毕后才开始执行。由此就出现了某一任务执行时间过长而造成的后续任务的等待问题。因此Javascript引入了异步的概念,它允许用另一个线程来管理异步任务,当某个异步任务达到可执行的条件时,便将该任务放在主线程队列中。

2. Javascript间歇调用和超时调用

Javascript提供间歇调用setInterval和超时调用setTimeout两种方法来实现异步编程。setInterval是指每隔指定的时间执行一次代码,setTimeout则是指在指定的时间过后执行代码。

setTimeout( )方法

该方法接受两个参数:要执行的代码和以毫秒为单位的时间。如下代码,会在1s后打印出’Hello World!’。

setTimeout(function () {
    console.log('Hello World!');
}, 1000);

虽然话说第二个参数表示要等待的时长,但现实可能等待的时间要大于这个时长。第二个参数指定了过多少毫秒把当前任务放到主线程队列中,此时如果队列为空,那么该代码会立即执行;如果队列不空,那么就要等前面的代码执行完后才可以执行。如下代码,我们会看到,虽然我们将时间设为0,但打印结果却不是World Hello,而是Hello World,这是由于打印world的代码准备执行的时候主线程队列不为空,所以结果是Hello World。

setTimeout(function () {
    console.log('World');
}, 0);
console.log('Hello');

运行结果

setInterval( )方法

该方法和setTimeout实现机制类似,只不过它会按照指定的时间间隔重复执行。也接受两个参数:要执行的代码(字符串或函数)和每次执行之前需要等待的毫秒数。如下代码,每隔1s就将要执行的代码放到主线程队列中。

setInterval(function () {
    console.log('Hello World!');
}, 1000);

这里需要注意的是,好多人会误认为第二个参数代表的时间间隔是指,在上一次代码执行完成后需要等待的时间间隔,但事实并非如此,不管上一次代码执行结果怎样,都会每隔固定的毫秒数将要执行的代码放到主线程队列中。

取消setTimeout和setInterval

调用setTimeout和setInterval都会返回一个数值ID,通过使用该ID可以取消超时调用和间歇调用。方法clearTimeout( )可以完全取消超时调用,方法clearInterval( )可以取消尚未执行的间歇调用。如下代码,变量i每隔1s递增一次并被打印,当i等于5时,间歇调用取消。

var i = 0;
var max = 5;
var intervalId = null;

function count() {
    i++;
    console.log(i);
    if (i === max) {
        clearInterval(intervalId);
        console.log('done');
    }
}

intervalId = setInterval(count, 1000);

3. 使用setTimeout模拟setInterval

一般在开发中,很少真正的使用setInterval,原因是后一个间歇调用可能会在前一个间歇调用结束之前启动。这就意味着我们某些次数的代码的执行可能会丢失。为了避免这一点,我们可以用setTimeout来模拟实现setInterval。那么怎样让setTimeout循环起来呢,这就用到了递归的思想。如下代码:函数foo内部实现了自身的递归,这样每隔1s函数foo就会执行一次。

var i = 0;

function foo() {
    i++;
    console.log(i);

    setTimeout(foo, 1000);
}

foo();

这种模拟setInterval的方法与setInterval本身还是有一些区别的。
第一,我们之前说到了setInterval会每隔固定的时长将要执行的代码放到主线程队列中,不管上一次代码执行结果如何;但使用setTimeout模拟的方法并非如此,此递归方法会在上一次代码执行结束那一刻,等待需要的时长,再开始下一次代码的执行。
第二,setInterval的第一次间隔调用前是要等待所需要的时长的,换句话说就是要等待相应的毫秒数才会第一次执行代码,但以上模拟的方法中第一次代码的执行是立即的。当然我们也可以通过改造上诉模拟方法来避免这个差异。代码如下:

var i = 0;

function foo() {
    function func() {
        i++;
        console.log(i);
    }

    setTimeout(function () {
        foo();
        func();
    }, 1000);
}

foo();

因此,尽量避免使用setInterval,而是选择用setTimeout来模拟setInterval。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值