首页 日常生活 社交礼仪 美容健身 电脑网络 手机技巧 电子数码 废物利用
首页 > 电脑网络 > 网站建设 > setTimeout原理和JavaScript运行机制详情

setTimeout原理和JavaScript运行机制

  • 2015-12-29 19:22:25
  • 阅读:...

一、诡异的setTimeout

setTimeout(code, ms)函数是指在指定的毫秒数(ms)后调用函数或执行代码块,并返回一个整数,后续可以通过clearTimeout(num)传递这个整数来取消该定时器。

setTimeout(function(){
    console.log(1);
}, 0);
console.log(2);

一个很普通的setTimeout定时器,运行上面的代码输出的结果是2、1,但是明明定时器是:在0ms也就是“立即”执行log(1),然后再log(2)啊,结果顺序却是反的,甚至在log(2)之前加上一个耗时的处理也不会影响这个输出结果:

var startTime = +new Date();
setTimeout(function(){
    console.log(1);
}, 0);
while((+new Date() - startTime) < (1000 * 3)){
    // console.log('...');
}
console.log(2);

以上加了一个3秒的while循环阻塞进程,按正常理解log(2)需要在log(1)后3秒才会输出,但输出结果还是跟之前一样,下面逐步分析这种情况的原因。

二、任务队列

JavaScript是单线程的语言,在执行时必须等前面的任务处理完以后才会处理后面的;而且是一个一个连续同步执行的,不象多线程可以同时处理多个任务。JavaScript中的任务分为同步任务和异步任务,同步任务就是主线程上一个个排队执行的任务;相反的异步任务则不进入主线任务而是被加入到“任务队列”中,任务队列的任务只有在主线任务执行完成之后才去处理任务队列中的任务

这样就可以解释上面的问题了:setTimeout(function(){console.log(1);}, 0);这里的0代表的是0秒后加入到任务队列并没有执行,他要等主线程上面的任务console.log(2)执行完成后才会执行。

setTimeout、setInterval和回调这两种形式的程序会添加到任务队列,示例如下:

function foo(){
	console.log(1);
}
function bar(){
	console.log(2);
}
foo();
bar();
$('#btn').on('click', function(){
	console.log(3);
});
setTimeout(function(){
    console.log(4);
}, 0);

主线程上的任务就是执行foo()、bar()和后面的事件绑定和设定定时器,而任务队列中有一个事件回调任务和一个定时器任务,主线程foo()、bar()执行结束后,就会询问任务队列是否有任务,然后“全部执行”。所以setTimeout(code, ms)表示的是ms后把code任务添加到队列,而不是说ms后就会执行,就算setTimeout时间设置成0,他也要等主线程上的任务完成才会执行,所以setTimeout的执行时间并不是准确的,往往真正执行的时间要比你设定的时间偏大。

三、单线程优缺点

缺点:

1、效率低,只能一个一个的来,这个是天生决定的,这也是JavaScript会阻塞页面渲染的原因之一。比如下面的代码:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
    <title>Document</title>
</head>
<body>
<input type="text" onkeydown="alert(this.value)">
<button id="btn">点我呀!!!</button>
<script>
    var btn = document.getElementById('btn');
    var body = document.body;
    btn.onclick = function(){
        body.style.background = '#ccc';
        var startTime = +new Date();
        while (+new Date() - startTime < 3 * 1000) {
        }
    };
</script>
</body>
</html>

当点击按钮时并不会象自己想的那样选改变body的背景色再去执行下面3秒的循环,UI的渲染是等js执行完成后执行的。查看demo

2、程序假死、无法效应,这点其实就是第一点效率低的后遗症,还是上面的例子当点击按钮后,你去点击input输入框但是他并没有获得焦点,这时线路无法响应用户的操作,就是啥也干不了,直到js执行完毕。

既然单线程这么挫,那么为什么还要用他呢,它还是有优点滴:

1、简单,连续的思维方式或许更容易让人接受

2、业务流程好控制,不象多线程任务那样执行顺序比较乱

四、setTimeout应用:性能优化

setTimeout做性能优化,由前文可以看出当执行JS时是不会响应用户操作的,更不会响应UI的更新,当然部分浏览器已经在做相应的优化:JS阻塞时会记录一部分任务如UI更新,等JS执行完后会执行之前记录的任务。但是也弥补不了阻塞时页面不受控制这样糟糕的用户体验。所以可以通过setTimeout分拆耗时较长的JS任务,让线程有空闲去响应UI的更新。

foo();
bar();
baz();

假如三个函数处理时间都很长,那么就可以用setTimeout把这些大任务分拆开来,这样线程就可以腾出时间来响应其他任务了。

var arr = [foo, bar, baz];
var len = arr.length;
var i = 0;
for(;i < len; i++){
	setTimeout(arr[i], 30);
}

这样做的代价是,任务相对于前面同步执行那种形式会有一定的延迟,并且执行任务的总时间会增加。

五、setTimeout中的this

setTimeout(code, ms)的code函数或者代码块最终是在全局上下文执行的,所以如果代码中有用到this就需要注意了。

var foo = {
	name: '噪点,lmqy.net',
	sayName: function(){
		setTimeout(function(){
			console.log(this.name)
		}, 200);
	}
}
foo.sayName(); //undefined

上面foo.sayName()输出undefined还是比较好理解的,但还有一种情况

var name = 'global';
var foo = {
	name: '噪点,lmqy.net',
	sayName: function(){
		console.log(this.name)
	}
}
setTimeout(foo.sayName, 200);

最后输出的是'global',跟上面的情况不同,上面那种是匿名函数在全局下面执行的,this肯定指向全局(window),而这里是foo.sayName()按理this应该是foo才对,自己感觉应该问题还是在setTimeout(foo.sayName, 200);这步的时候应该是把foo.sayName的函数返回了,所以最终执行的是foo.sayName的函数体而不是foo.sayName,有点类似下面这种情况,不晓的理解的对不对?

var bar = foo.sayName;
bar();

六、setTimeout时间大小

setInterval和setTimeout很多地方都是一样的机制,包括上面提到的还有就是时间,比如用setTimeout来模拟setInterval的效果

var startTime;
var t;
var i = 0;
function foo(){
	startTime = startTime ? startTime : +new Date();
	if((+new Date() - startTime) > (1000 * 10)){ //5秒后退出
		clearTimeout(t);
		console.log(i);
	}else{
		i++;
		t = setTimeout(foo, 1000);		
	}
}
foo();

10秒输出结果是10,如果把setTimeout(foo, 1000)时间改小输出的结果就会比理论计算的结果偏小,网上流传建议时间设置大于15ms,甚至有说部分浏览器优化可以实现>=4ms频率的执行,但我用谷歌浏览器测试出来的结果还是偏小,个人感觉除了硬件上的因素外任务队列也会影响,但没有找到权威一些的答案。

相关文章推荐:

1.settimeout怎么用?JS中setTimeout()的用法详解

2.setTimeout用法:js函数setTimeout延迟执行的简单介绍

网站建设热点文章