前端性能之非阻塞加载js脚本

前端性能之非阻塞加载js脚本

分类:js/css/htmlweb

SCRIPT标签的阻塞行为会对页面的性能产生影响,这是因为浏览器在下载脚本、解析、执行的过程中不会同时做其他事情,比如渲染页面、响应用户事件等。之所以这样做是因为正在执行的JavaScript代码可能会改变页面元素、修改样式、添加或者删除事件等各种操作,以及最关键的脚本之间的依赖性,浏览器必须等待当前执行的脚本执行完成之后再进行后续操作。

脚本阻塞两种加载方式

HTML页面中的JavaScript脚本有两种方式加入 – 使用script标签内联到HTML页面,页面按从上到下的顺序执行到script标签处时执行js代码,后续HTML内容会被阻塞。 – 使用script标签的src属性将js文件从外部加载,这需要浏览器查询对应文件的缓存,如果不可用就要重新进行http请求,这样就又会产生网络延迟和下载后的解析与执行,这都会阻塞页面。

浏览器特性

一般情况下,大多数浏览器支持并行下载html、css、图片等元素,不过对于同一个域名下的资源,浏览器默认最多并行下载的个数有限制,一般是4个。另外,对于JavaScript脚本,浏览器却不支持并行下载,当下载一个脚本并解析、执行后,才能执行后一个。 浏览器之所以保证不能并行下载多个脚本,是为了防止两个有依赖的脚本在浏览器的执行顺序颠倒后,会引发变量、函数未定义的错误。同时也会更改html内容。因此,脚本必须要顺序地执行,但是这并不代表它们必须要顺序地下载。 IE8是第一个支持并行下载JavaScript脚本的浏览器,这使得页面加载多个脚本的速度加快了很多,但是这并没有解决脚本执行的阻塞问题,当A.js和B.js并行下载之后,它们依然要进行解析和顺序执行,这段时间必须要阻塞浏览器的其他行为,也就是等这段时间过了之后才能下载后续图片、css、iframe等元素。Chrome 2+和Safari 4+浏览器也是和IE8类似,会并行下载脚本但是不能 因此,最终的目的是要并行下载脚本的同时,也能下载其他元素而不会有阻塞的问题。这里都以外部脚本文件的加载来说明。

非阻塞加载外部脚本

为了避免脚本的阻塞问题,最简单的方式就是讲所有JavaScript脚本内联到HTML中,将脚本放在所有可显示元素最后面,就可以避免这个问题,但是对于大型的js文件以及缓存js文件的考虑,这个问题需要进行折中处理。针对外部的js文件请求,主要有如下几个方式进行

XHR Eval

使用XMLHTTPRequest对象从服务器异步获取js脚本文件,当响应完成后使用JavaScript语言的eval函数对响应内容进行执行。 优点:异步请求的js文件不会阻塞其他元素(图片、css等)的下载,脚本异步下载完成之后就执行。浏览器不显示”等待“。 缺点:请求的js文件必须要与主页面在同一个域名下,这对于CDN或者多域名的处理不便。不能保证执行顺序。

var xhrObj = getXHRObject();xhrObj.onreadystatechange = (xhrObj.readyState == 4 && xhrObj.status == 200){//依赖文件队列处理eval(xhrObj.responseText);//后续处理}};xhrObj.open(‘GET’, ‘a.js’, true);xhrObj.send(”);

一般为了保证异步加载的js文件的依赖性,需要手动保存好依赖文件队列,使其按依赖顺序执行。

XHR Injection

与XHR Eval类似,XHR Injection将异步获取的内容使用动态创建script标签的形式插入到DOM元素中去。实际测试显示使用eval方法会比这种方法的速度慢一些。

var xhrObj = getXHRObject();xhrObj.onreadystatechange = (xhrObj.readyState == 4 && xhrObj.status == 200){//依赖文件队列处理var script = document.createElement(‘script’);document.getElementsByTagName(‘head’)[0].appendChild(script);script.text = xhrObj.responseText;//后续处理}};xhrObj.open(‘GET’, ‘a.js’, true);xhrObj.send(”);

这种方法的优缺点与XHR Eval差不多,,但是速度可能会快一些。

Script in Iframe

iframe可以与主页面的其他元素并行下载,并且不会阻塞。但是iframe是为了包含其他的HTML页面,其他的HTML页面也可以包含js脚本,因此可以将需要加载的js脚本放入一个html文件中然后使用iframe非阻塞加载这个html文件即可。 优点:异步加载脚本,浏览器支持较好 缺点:需要与主页面同一个域名,需要将外部的js文件转换为html从而作为iframe的src属性。另外,iframe是一个非常重量级的DOM元素。不能保证执行顺序。浏览器会显示”等待“。 iframe本身也都可以使用js脚本进行动态创建:

var _ = function(d){document.getElementById(d);};{typeof a == “string” && (a = _(a));a.parentNode.removeChild(a) } catch (b) {}};var addEvent = function(ele, event, call){ele.addEventListener ? ele.addEventListener(event, call, !1) : a.attachEvent ? a.attachEvent(“on” + event, call) : a[“on” + event] = call;};var loadScriptByIframe = function(id, src){src == null && (src = “javascript:false;”);removeNode(id);var c = document.createElement(‘iframe’);c.height = 0;c.width = 0;c.style.display = “none”;c.name = id;c.id = id;c.src = src;c.isReady = !1;addEvent(c, (! c.isReady){c.isReady = !0;//当前脚本已加载完成,执行其他js代码}});document.body.appendChild(c);window.frames[id].name = id;return c;};从哪里跌倒就会从哪里爬起来,让我们一起努力吧

前端性能之非阻塞加载js脚本

相关文章:

你感兴趣的文章:

标签云: