JavaScript欲速则不达——时间函数

异步而非线程

曾经我一直以为使用setTimeout()、setInterval()、XMLHttpRequest 和事件处理程序等能让javascript异步执行,不阻碍脚本运行,就是多线程运行了。后来发现原来这原来都是假象。

假设有两个setTimeout(),如下:

alert(time1); // undefined
var time = setTimeout(function() {
    while (true) {
    	alert(time1); // 3
    };
}, 15);
var time1 = setTimeout(function() {
    alert(time);  // 2当然2是不可能出现的
}, 15);
		

以上代码可以发现:既然setTimeout()不是增加线程的,那应该是按顺序执行,第一个setTimeout()代码中alert的也是undefined,但怎么alert的是3。

参考网上的资料,看看单线程的javascript是如何骗过我们的?

javascript是单线程的,也就是说,在同一时间内,只能有一段代码被 javascript 引擎执行。如果同一时间还有其他代码要执行的话,则这些代码需要等待 javascript 引擎执行完成当前的代码之后才有可能获得执行的机会。正常情况下,javascript采用的是事件驱动编程,首先javascript会顺序执行页面上的所有 javascript 代码,之后javascript引擎进入空闲状态,最后再执行触发事件上的 javascript 代码,譬如用户的点击事件等。javascript中有一个待处理的事件队列,如果在执行过程中,有新的事件处理方法则会先将他们加入到队列中等待执行。

所以为什么上例中第一个setTimeout()中alert的是3而不是undefined了,javascript将setTimeout()中的代码执行加入到等待队列中,而此时javascript引擎已经执行完了所有的代码了,还没轮到的事件代码还在事件队列中排队。

javascript是基于事件驱动的单线程函数,所有写在事件中的任务实体都是回调函数,这些回调函数都会按照时间间隔在那排着队等待javascript引擎来执行它们。

这个队伍中排在第一个位置的永远是正在执行的回调函数(排在前面的优先级高);第二位则是用户的操作事件中的回调函数;之后的则是在时间函数中的回调函数,它们按照各自的时间间隔在那队伍中一直往下排着队等待执行。

事件驱动编程其实在我们生活很常见,假设你在煮饭,正在切菜的时候锅里的东西沸溢了,你会暂停切菜,把炉火关小。而不会在切菜的同事把火关小。事件驱动编程也是同样的道理,通过让程序员一次只能为一个回调函数编写处理代码,可以让代码能够快速的处理多个任务。

所以setTimeout不能新建线程,而是假象。而事件驱动编程却很好的解决了阻塞的问题,所以在一个用时间函数的页面里,你还是可以去操作页面上的元素。

异步的计时函数

而有些时候,我们只是想要函数在将来某个时候运行。比如一个需要较长执行时间的任务或者模拟动画。基于时间的事件函数即:setTimeout和setInerval。

可惜的是,这两个基于时间的事件函数都有自己的一些小缺陷。

其一就是以上说的:当同一个javascript代码正运行着代码时,任何javascript计时代码都无法使其他代码运行起来。

其二就是这两个计时函数就是设计成慢吞吞的。如下

var fireCount = 0;
var start = new Date;
var timer = setInterval(function(){
	if (new Date-start >1000){
		clearInterval(timer);
		console.log(fireCount);  //按理论上应该是1000,但是事实上却不是。
		return;
	}
	fireCount++;
},0)
		

所以要明确这两个计时函数就是不精确的的计时工具。这两个计时函数当初就是被设计成延迟函数的

Node.js也是采用事件驱动编程。在node中,要精确计时就使用process.nextTick;在浏览器端,在支持requestAnimationFrame的浏览器中使用requestAnimationFrame;不支持的则退而使用setTimeout。

其中有些函数就完全是异步执行的。而有些则是有些时间是异步执行,譬如Jquery的DOMload函数。若DOM早已加载完毕,则$回调将会立即触发。

看了以上才发现我们一直以为的时间函数不是线程函数,却是假象。HTML5中的Web Workers为 JavaScript 引入真正的线程技术。Web Workers以后再开篇文章来讲诉

本文源链接:http://www.html5jscss.com/js-settimeout.html

转载请注明《JavaScript欲速则不达——时间函数》| html5jscss

评论关闭了.