js定时器setTiemout、setInterval

JS提供了一些原生方式来实现延时去执行某一段代码,下面来简朴先容一下setTiemout、setInterval、setImmediate、requestAnimationFrame。 一、什么是定时器 JS提供了一些原生方式来实现延时去...

JS提供了一些原生方式来实现延时去执行某一段代码,下面来简朴先容一下setTiemout、setInterval、setImmediate、requestAnimationFrame。


一、什么是定时器

JS提供了一些原生方式来实现延时去执行某一段代码,下面来简朴先容一下。

setTimeout: 设置一个定时器,在定时器到期后执行一次函数或代码段

var timeoutId = window.setTimeout(func[, delay, param1, param2, ...]);
var timeoutId = window.setTimeout(code[, delay]);
  • timeoutId: 定时器ID
  • func: 延迟后执行的函数
  • code: 延迟后执行的代码字符串,不推荐使用原理类似eval()
  • delay: 延迟的时间(单米:毫秒),默认值为0
  • param1,param2: 向延迟函数通报而外的参数,IE9以上支持

setInterval: 以牢固的时间距离重复挪用一个函数或者代码段

var intervalId = window.setInterval(func, delay[, param1, param2, ...]);
var intervalId = window.setInterval(code, delay);
  • intervalId: 重复操作的ID
  • func: 延迟挪用的函数
  • code: 代码段
  • delay: 延迟时间,没有默认值

setImmediate: 在浏览器完全竣事当前运行的操作之后立刻执行指定的函数(仅IE10和Node 0.10+中有实现),类似setTimeout(func, 0)

var immediateId = setImmediate(func[, param1, param2, ...]);
var immediateId = setImmediate(func);
  • immediateId: 定时器ID
  • func: 回调

requestAnimationFrame: 专门为实现高性能的帧动画而设计的API,然则不能指定延迟时间,而是凭据浏览器的刷新频率而定(帧)

var requestId = window.requestAnimationFrame(func);
  • func: 回调

上面简朴的先容了四种JS的定时器,而本文将会主要先容对照常用的两种:setTimeout和setInterval。


二、举个栗子

基本用法

// 下面代码执行之后会输出什么?
var intervalId, timeoutId;

timeoutId = setTimeout(function () {
    console.log(1);
}, 300);

setTimeout(function () {
    clearTimeout(timeoutId);
    console.log(2);
}, 100);

setTimeout('console.log("5")', 400);

intervalId = setInterval(function () {
    console.log(4);
    clearInterval(intervalId);
}, 200);

// 划分输出: 2、4、5


setInterval 和 setTimeout的区别?

// 执行在面的代码块会输出什么?
setTimeout(function () {
    console.log('timeout');
}, 1000);

setInterval(function () {
    console.log('interval')
}, 1000);

// 输出一次 timeout,每隔1S输出一次 interval

/*--------------------------------*/

// 通过setTimeout模拟setInterval 和 setInterval有啥区别么?
var callback = function () {
    if (times++ > max) {
        clearTimeout(timeoutId);
        clearInterval(intervalId);
    }

    console.log('start', Date.now() - start);
    for (var i = 0; i < 990000000; i++) {}
    console.log('end', Date.now() - start);
},
delay = 100,
times = 0,
max = 5,
start = Date.now(),
intervalId, timeoutId;

function imitateInterval(fn, delay) {
    timeoutId = setTimeout(function () {
        fn();

        if (times <= max) {
            imitateInterval(fn ,delay);
        }
    }, delay);
}

imitateInterval(callback, delay);
intervalId = setInterval(callback, delay);

若是是setTimeout和setInterval的话,它俩仅仅在执行次数上有区别,setTimeout一次、setIntervaln次。

而通过setTimeout模拟的setInterval与setInterval的区别则在于:setTimeout只有在回调完成之后才会去挪用下一次定时器,而setInterval则不管回调函数的执行情况,当到达划定时间就会在事宜行列中插入一个执行回调的事宜,以是在选择定时器的方式时需要思量setInterval的这种特征是否会对你的营业代码有什么影响?


setTimeout(func, 0) 和 setImmediate(func)谁更快?(仅仅是好奇,才写的这段测试)

console.time('immediate');
console.time('timeout');

setImmediate(() => {
    console.timeEnd('immediate');
});

setTimeout(() => {
    console.timeEnd('timeout');
}, 0);

在Node.JS v6.7.0中测试发现setTimeout更早执行


面试题

下面代码运行后的效果是什么?

// 问题一
var t = true;
 
setTimeout(function(){
    t = false;
}, 1000);
 
while(t){}
 
alert('end');

/*--------------------------------*/

// 问题二
for (var i = 0; i < 5; i++) {
    setTimeout(function () {
        console.log(i);
    }, 0);
}

/*--------------------------------*/

// 问题三
var obj = {
    msg: 'obj',
    shout: function () {
        alert(this.msg);
    },
    waitAndShout: function() {
        setTimeout(function () {
            this.shout();
        }, 0);    
    }
};
obj.waitAndShout();

问题谜底会在后面解答


三、JS定时器的事情原理

在注释上面问题的谜底之前我们先来领会一下定时器的事情原理,这里将用引用How JavaScript Timers Work中的例子来注释定时器的事情原理,该图为一个简朴版的原理图。


上图中,左侧数字代表时间,单米毫秒;左侧文字代表某一个操作完成后,浏览器去询问当前行列中存在哪些正在守候执行的操作;蓝色方块示意正在执行的代码块;右侧文字代表在代码运行历程中,泛起哪些异步事宜。该图大致流程如下:

  • 程序最先时,有一个JS代码块最先执行,执行时长约为18ms,在执行历程中有3个异步事宜触发,其中包罗一个setTimeout、鼠标点击事宜、setInterval
  • 第一个setTimeout先运行,延迟时间为10ms,稍后鼠标事宜泛起,浏览器在事宜行列中插入点击的回调函数,稍后setInterval运行,10ms到达之后,setTimeout向事宜行列中插入setTimeout的回调
  • 当第一个代码块执行完成后,浏览器查看行列中有哪些事宜在守候,他取出排在行列最前面的代码来执行
  • 在浏览器处置鼠标点击回调时,setInterval再次检查到到达延迟时间,他将再次向事宜行列中插入一个interval的回调,以后每隔指定的延迟时间之后都市向行列中插入一个回调
  • 后面浏览器将在执行完当前队头的代码之后,将再次取出现在队头的事宜来执行

这里只是对定时器的原理做一个简朴版的形貌,现实的处置历程比这个庞大。


四、问题谜底

好啦,我们现在再来看看上面的面试题的谜底。

第一题

alert永远都不会执行,由于JS是单线程的,且定时器的回调将在守候当前正在执行的义务完成后才执行,而while(t) {}直接就进入了死循环一直占用线程,不给回调函数执行机遇  

第二题

代码会输出 5 5 5 5 5,理由同上,当i = 0时,天生一个定时器,将回调插入到事宜行列中,守候当前行列中无义务执行时立刻执行,而此时for循环正在执行,以是回调被弃捐。当for循环执行完成后,行列中存在着5个回调函数,他们的都将执行console.log(i)的操作,由于当前JS代码上中并没有使用块级作用域,以是i的值在for循环竣事后一直为5,以是代码将输出5个5  

第三题

这个问题涉及到this的指向问题,由setTimeout()挪用的代码运行在与所在函数完全星散的执行环境上. 这会导致这些代码中包罗的this关键字会指向window (或全局)工具,window工具中并不存在shout方式,以是就会报错,修改方案如下:  
var obj = {
    msg: 'obj',
    shout: function () {
        alert(this.msg);
    },
    waitAndShout: function() {
        var self = this; // 这里将this赋给一个变量
        setTimeout(function () {
            self.shout();
        }, 0);    
    }
};
obj.waitAndShout();


五、需要注重的点

setTimeout有最小时间距离限制,HTML5尺度为4ms,小于4ms根据4ms处置,然则每个浏览器实现的最小距离都差别,由于JS引擎只有一个线程,以是它将会强制异步事宜排队执行

若是setInterval的回调执行时间长于指定的延迟,setInterval将无距离的一个接一个执行

this的指向问题可以通过bind函数、界说变量、箭头函数的方式来解决


思源资源网:分类流动

1.阿里云: 本站现在使用的是阿里云主机,平安/可靠/稳固。点击领取2000米代金券、领会最新阿里云产物的种种优惠流动点击进入

2.腾讯云: 提供云服务器、云数据库、云存储、视频与CDN、域名等服务。腾讯云各种产物的最新流动,优惠券领取点击进入

3.广告同盟: 整理了现在主流的广告同盟平台,若是你有流量,可以作为参考选择适合你的平台点击进入

链接: http://www.fly63.com/article/detial/3131

  • 发表于 2021-04-05 14:07
  • 阅读 ( 189 )
  • 分类:互联网

0 条评论

请先 登录 后评论
q2296
q2296

742 篇文章

你可能感兴趣的文章

相关问题