@yacent
2016-10-21T17:28:42.000000Z
字数 2038
阅读 1209
性能优化
加载的顺序,浏览器在获取了一个html文档时,会 自上而下 地进行加载,在加载过程中进行解析渲染
如前所述,网络的模型是同步的。网页作者希望解析器遇到 <script>
标记时立即解析并执行脚本。文档的解析将停止,直到脚本执行完毕。如果脚本是外部的,那么解析过程会停止,直到从网络同步抓取资源完成后再继续。
加载
原因:
JS有可能会修改DOM,最为经典的document.write,这意味着,在JS执行 完成前,后续所有资源的下载可能是没有必要的,这是js阻塞后续资源下载的根本原因。
办法:
可以将外部引用的js文件放在</body>前。
浏览器的五个常驻线程
- 浏览器GUI渲染线程
- JavaScript引擎线程
- 浏览器定时器触发线程(setTimeout)
- 浏览器事件触发线程
- 浏览器http异步请求线程
注意:这里涉及到 阻塞 的现象,当js引擎线程(第二个)进行时,会挂起其他一切线程
加载过程js文件优化方式:
1. prefetch 一般现在的浏览器也已经做了这个优化,会并行地发送文件请求,但是执行与否要等到真正调用的时候才会执行,还是会阻塞其他
2. 放在body后面,这个还是比较常用的,不会阻塞DOM树的构造
3. defer async: defer的话,延迟,在onload事件前触发,就是烦在js文件之间必须按顺序写,因为存在依赖关系,但是可以用模块化解决(AMD CMD之中个 loader),async的话,异步,但是有个缺点,是他们真正到达的时间不确定,哪个下载好了就执行,这给js之间存在依赖关系时,带来很大的问题
<script>标签尽可能放到 <body> 标签的底部,以尽量减少对整个页面加载、解析、渲染的影响
由于每个<script>标签初始下载会阻塞页面渲染,故减少页面包含的<script>标签数量有助于改善这依情况。因为HTTP请求的延迟影响,过多的文件请求会带来性能的开销。应根据实际情况,进行相对应文件的合并。
但是,不要一味地进行合并,因为如果合并后,文件过大,对于请求等待的时间,也会很长,网页将会有一段时间失去响应,这交互也不好。
关键在于 页面加载完成后 才加载JavaScript代码,即window对象的onload事件触发后再下载脚本
defer:
执行时机:DOM加载完成之前,即将要完成的时候,实际效果和 放在底部 类似
脚本会延迟加载,即在DOM完成加载之后,才进行加载,解析和执行,但是其兼容性不好,目前只有IE和firefox支持,其余浏览器都忽略该属性,而且,js文件的顺序必须按顺序写,才能解决依赖性的问题
async:
异步地加载和执行脚本,但是async情况下,js脚本一旦下载好就会执行,可能不按照原本的顺序来执行,故文件之间的依赖关系也很难维护
将以上三者用一个函数来进行封装,如下
function loadScript(url, callback) {
var script = document.createElement('script');
script.type = 'text/javascript';
if (script.readyState) { // IE
script.onreadystatechange = function() {
if (script.readyState == "loaded" || script.readyState == "complete") {
script.onreadystatechange = null;
callback();
}
};
} else { // others
script.onload = function() {
callback();
};
}
script.src = url;
document.getElementsByTagName('head')[0].appendChild(script);
}