《高性能网站建设进阶指南》css
按理来讲,JavaScript在浏览器中的性能问题是开发人员面对的最重要的可用性问题。但因为JavaScript天生的阻塞性质,问题变得复杂。大多数浏览器在下载或者执行脚本的同时不会下载其余内容,使用单线程处理JavaScript的解析和UI的更新。当遇到这种状况时,但愿以不阻塞其余内容下载的方式来加载JavaScript。有些技术能够作到这点,使页面加载更快。html
在介绍JavaScript加载优化技术以前,先看看浏览器默认的方式。<script> 标签能够放在 <head> 或者 <body> 里面的任意位置。通常来讲都将 <script> 和 <link> 标签一块儿放在 <head> 中,这样一来页面加载的时候会先加载它们,页面的样式和行为看起来正常。跨域
<html> <head> <meta charset="UTF-8"> <title>Demo</title> <link rel="stylesheet" href="css/base.css"> <link rel="stylesheet" href="css/base2.css"> <script src="scripts/file1.js"></script> <script src="scripts/file2.js"></script> <script src="scripts/file3.js"></script> </head> <body> <p>Hello,CrispElte</p> </body> </html>
尽管这端代码开始来无伤大雅,但实际上存在几个性能问题:有三个脚本文件,每一个文件在下载和执行时候都会阻塞页面的加载。只有脚本执行完成以后,才会继续加载其余资源,好比,图片,CSS文件,iframe等。
咱们能够将 <script> 标签放在页面的底部,即 </body>标签以前。尽管脚本文件的加载会阻塞页面,可是页面在脚本呢加载以前已经加载完成,因此不用担忧阻塞。
脚本应该顺序执行,可是没有必要顺序下载。IE8第一次实现了脚本的并行下载,可是在脚本下载并执行完毕以前依旧阻塞了后面的资源。
最终的目的时让脚本与其余资源并行下载,而且但愿兼容全部的浏览器。浏览器
有几种动态加载外部脚本的技术可使页面不会被脚本的阻塞行为所影响。app
经过XMLHttpRequest从服务端获取脚本,而后经过eval命令执行内容dom
var xhrObj=new XMLHttpRequest(); xhrObj.onreadystatechange=function(){ if(xhrObj.readyState == 4 && xhrObj.status == 200){ eval(xhrObj.responseText); } } xhrObj.open("GET","file1.js",true); xhrObj.send(null);
这个方法的主要缺陷是,动态加载的脚本必须是同域的。async
与XHR Eval相似,一样是经过 XMLHttpRequest 对象来获取脚本,不一样之处在于,这个方法时不是用 eval 而是建立一个 script 的 DOM 元素,而后将 XMLHttpRequest 的响应写入script标签中来执行JavaScript。性能
var xhrObj=new XMLHttpRequest(); xhrObj.onreadystatechange=function(){ if(xhrObj.readyState == 4 && xhrObj.status == 200){ var script=document.createElement("script"); document.getElementsByTagName("head")[0].appendChild(script); script.text=xhrObj.responseText; } } xhrObj.open("GET","file1.js",true); xhrObj.send(null);
和 XHR Eval 方法同样,加载的脚本必须是同域的。优化
在页面中 iframe 与其余资源是并行下载的,能够利用iframe无阻塞加载JavaScript。
因为 iframe 认为返回的是 HTML 文档,因此将src设置成一个 HTML 文件而不是 js 文件。
而咱们要作的就是在 HTML 文档中将外部脚本转换成行内脚本。网站
与 XHR Eval 和 XHR 注入这两种方法相似,这个方法要求 iframe URL 和主页同域。知足同域要求以后,咱们须要修改 JavaScript 来建立他们之间的关联,其本质就是得到引用 iframe 的 JavaScript 标示符。
//使用 "iframes" 中访问主页上的 iframe window.frames[0].somefunction(); //使用 "getElementById" 访问主页上的iframe document.getElementById("myIframe").contentWindow.someFunction();
能够在iframe中使用parent变量引用父页面
function changeBg(){ var body=parent.document.body; body.className="red"; }
归纳一下:主页面中添加一个 iframe 标签,其 src 指向一个 HTML 文档,在这个 HTML 文档中编写行内 JavaScript 代码,也能够引用外部的 JavaScript 文件
建立一个script标签并设置其src,代码很简单。
var script=document.createElement("script"); script.src="demo2.js"; document.getElementsByTagName("head")[0].appendCHild(script);
下载过程当中用这种方式建立脚本不会阻塞其余的资源,同时这种方法容许跨域。
在最新的标准中,script标签订义了defer属性和async属性,都是让脚本并行下载,可是defer下脚本按照顺序执行,而async不按顺序执行脚本。
最后一种技术是使用 document.write 把 HTML 标签 script 写入页面中。这种技术只在IE中是并行加载脚本的。虽然多个脚本能够并行下载,但在下载脚本时,浏览器仍然阻塞其余类型的资源。