javascript异步加载
转载自 http://www.ilovejs.net/archives/1322
javascript的加载方式,总得来说是在页面上使用script来声明,以及动态的加载这些方式,而动态的加载,在很多js库中都能够很好的去处理,从而不至于阻塞其他资源的加载,并与其并行加载下来。这样的动态异步的加载方式罗列起来有:Ajax的方式、DOM Element Insert、Iframe、document.write、defer等等。这些都能够很好的处理js在加载的时候不会阻塞资源加载的问题,但是,js的执行仍然会阻塞浏览器的渲染。或许这是不得不需要付出的代价,有没有一些方式去缓解js在执行的时候对浏览器的渲染所造成的延迟的影响呢?
首先,让我们从UI Thread、UI Queue、UI Upate的角度去分析整个页面和javascript的行为。浏览器在加载HTML到最后呈现出来的这段过程,整个就是一个UI Thread进程,这个UI Thread里是一个浏览器的响应队列,而UI Queue则是浏览器的行为队列,包括UI Update,javascript的执行行为。那么在页面加载的过程中,UI Queue里面就储存了UI Update、js加载、js解析、js执行等。不管是UI Thread,还是UI Queue,都是按照顺序来的。页面在刚开始未遇到js的加载和执行的时候,是UI Update的一个过程,一旦遇到js,就会等待js的加载、解析、执行完毕之后,接着又开始UI Update,如此这样的一个相应顺序。
那么当js的加载是异步了之后呢,这个时候,js的加载和解析不会在UI Queue的执行队列里,而是等到js加载、解析完毕,一到执行的时候,就添加到UI Queue队列中,从而阻塞了UI Queue中后面的行为(UI Update)的执行。这就是开头所说的在js的执行期总会阻塞页面的渲染,也就是UI Update。但是这个动态加载的方式跟普通在页面中使用script标签来加载的时候的优势是:将js的加载、解析的行为独立出来,不影响浏览器的UI Update,知道执行期才阻塞。这就很多的程度上加快了页面的渲染和展现。
再来说说defer和async属性,defer属性最开始是为IE所实现的,现代的浏览器也都逐渐实现了,那么它的工作原理是什么呢。它的作用跟上面动态加载的优势很相同,js的加载和解析是独立的,但是有一点不同的是:使用了defer属性之后,js代码会等到DOM加载完成的时候才执行,这个时候就又更大限度的让浏览器尽快的UI Update部分完成,让js的执行对浏览器的渲染所造成的影响更小化。那么async呢,是跟上面所说的动态加载js的优势是一样的,也是独立js的加载、解析,解析完成的时候就立即添加到UI Queue队列中去等待执行,阻塞后面的UI Update行为。
那么怎样将js的执行对UI Update的影响更小呢?使用HTML5的Worker机制吧,将复杂的js执行交给Worker去执行,Worker是一个独立的js执行环境,这个环境里没有window、DOM的概念,只是用来处理复杂的运算,再将处理后的结果通过postMessage方法发送会浏览器,Worker和页面之间通过postMessage方法来实现跟浏览器的数据交换。这样,将复杂运算交给Worker之后,在页面中所执行的js代码,将会是大大的减小,减小到只需要处理一个onmessage事件,将页面的js执行时间最小化。