首页 > 代码库 > js异步模型
js异步模型
前言:虽然关于js异步模型的文章已经是相当多,前端们对其也都是有各自的理解。本文的目的是梳理一下我对js异步模型的理解,以及希望给其他前端在这方面提供一个参考。本文只讲js异步模型,下一篇文章再去扯promise/a标准,jquery的promise和deferred对象。本文主要说的是浏览器端的js异步。下面罗列一下关于这方面的资料:JavaScript异步编程:设计快速响应的网络应用(这本书是为数不多专门讲js异步的书),别人写的关于js异步的文章(js异步编程1,js异步编程2),浏览器内部原理(这篇文章非常长,我只看了前面的一部分)。还有一些内容雷同的文章我就不列举了。
js的异步和java的异步是完全不一样的。java的异步是多个线程同时工作,用同步锁的方式实现同步资源的访问。而js的异步是基于事件的,多个线程往可执行事件队列里塞可执行事件来实现异步,这种方式保证了同一时刻只有一个线程在访问同步资源。先上图(纯手绘,略难看):
此处的事件可以理解为一个代码段,其通常的形式是一个回调函数。事件处理程序会不停的检查事件队列中是否有可执行的事件,如果有就会执行该事件。这些可执行事件是由两个线程生成的,时间线程和I/O线程。setTimeout,setInterval函数会设置时间线程在之后的某个时刻或多个时刻往事件队列上塞事件。ajax,dom的事件注册,worker的注册,postMessage等,都会在I/O线程上注册,让其在某个行为触发时,往事件队列上扔事件。以下就举个例子。
首先创建aysnc.html,代码如下:
<html> <head>aysnc</head> <body>
<div id=‘domAysnc‘>test</div> <script type="text/javascript" src=http://www.mamicode.com/‘aysnc.js‘></script> >
aysnc.js的代码如下:
var dom=document.getElementById(‘domAysnc‘);dom.onclick=function(){ console.log(‘I/O event‘);};window.setTimeout(function(){ console.log(‘time event‘);},0);
访问aysnc.html这个资源,浏览器会加载aysnc.js这个文件并交给js引擎解释并执行。当执行dom.onclick=....这条语句时,I/O线程会被注册一个事件,当dom被点击时就会触发I/O线程往事件队列上塞入这个事件。这个触发的过程和调用dom.click()是不同,是异步和同步的区别。当执行window.setTimeout...这条语句时,时间线程会被注册一个事件,0这个实参表示立即往事件队列上塞事件,实际上时间线程生成一个事件(以及事件处理程序的轮询)是需要时间的,最快的引擎大概是6ms左右。
下面来说一下window.setTimeout的一些应用。首先是动画,在非现代浏览器下(包括ie9),动画都是用window.setTimeout或window.setInterval来实现,把大的变化切分成一个个小的变化,然后用一个个很小的时间(在jquery中,这个很小的时间是13ms。)去执行这些小变化。这里面就会让js引擎不停的生成、执行事件,然后更新UI。而在现代浏览器下被支持的transition,可以指定某个属性的过渡效果。他并不牵涉js的执行,所以效率会高很多。
window.setTimeout同样可以用于大任务的拆分。比如在js上处理很大的一个数组,如果放在一个事件里处理,是会阻塞事件处理程序的。window.setTimeout(function(){\*拆分成的小任务*\},2);,用类似的做法,如果别的事件被触发,就可以被执行。
js异步模型