初学者,特别是自学的孩子,在学习的过程中常会遇到各种各样的瓶颈,例如:如何写好javascript、要注意什么等等。这篇文章中,总结了过去javascript一些高效的写法,供大家参考。
脚本
1 脚本数量
每个<script>标签初始下载时都会阻塞页面渲染,减少页面包含的<script>标签数量有助于改善这一情况。同时,不仅是针对外链脚本,内嵌脚本的数量同样也要限制。浏览器在解析HTML页面的过程中每遇到一个script标签,都会因执行脚本而导致一定的延时,因此最小化延迟时间将会明显改善页面的总体性能。
考虑到HTTP请求会带来额外的性能开销,因此下载单个100KB的文件将比下载4个25KB的文件更快。所以,减少页面中外链脚本文件的数量将会改善性能。
减少JS文件大小并限制HTTP请求数仅仅是创建响应迅速的Web应用的第一步。尽管下载单个较大的JS文件只会产生一次HTTP请求,但这么做会锁死浏览器一大段时间。因此,避免这种情况,你需要向页面中逐步加载JS文件。
无阻塞脚本的好处在于页面加载完成后才会加载JS代码。即,在window.load事件触发后才会下载脚本。
HTML4中引入一个script标签扩展属性:defer。该属性指明元素所含的脚本不会修改DOM,代码能安全地延迟执行。
同时,HTML5中引入async属性,用于异步加载脚本。async与defer的相同点是采用并行下载,在下载过程中不会产生阻塞。区别在于执行时机,async是加载完成后自动执行,defer需要等待页面完成后执行。
如下:
let script = document.createElement("script");
script.src = "1.js";
document.head.appendChild(script);
这个新建的script元素加载了1.js文件。文件在该元素被添加到页面时开始下载。这种方式的重点在于:无论何时启动下载,文件的下载和执行过程不会阻塞页面其他进程。甚至,你可以将代码插入到<head>区域而不会影响页面其他部分。因为,一般而言,把新建的<script>标签添加到<head>标签里比添加到<body>里保险,尤其是在页面加载过程中执行代码时更是如此。当<body>中的内容没有全部加载完成,IE可能会抛出一个“操作已终止”的错误信息。
使用动态脚本加载文件,返回的代码通常会立即执行。但是,当代码只包含供页面其他脚本调用的接口时,就会出问题。在这种情况下,你必须跟踪并确保脚本下载完成且准备就绪:
<script>元素接收完成时会触发一个load事件。你可以通过监听该事件来获得脚本加载完成时的状态:
let script = document.createElement("script");
script.onload = function() {
console.log("script loaded!");
}
script.src = "1.js";
document.head.appendChild(script);
而IE支持另一种实现方式,它会触发一个readystatechange
事件,script
元素提供一个readyState
属性,它的值在外链文件的下载过程的不同阶段会发生变化,其取值如下:
实际中,最有用的两个状态是"loaded"和"complate"。IE下,readyState的值并不一致,有事到达loaded状态不会到达complate;有时甚至不经过loaded就到达complate。所以,最保障的方式是对两种状态同时检查,只要有一个触发,就移除readystatechange事件处理器。下面,我们把这个过程放在一个函数中处理:
function loadScript(url,callback) {
let script = document.createElement("script");
if(script.readyState) {
script.onreadystatechange = function() {//IE
if(script.readyState == "loaded" || script.readyState == "complate") {
script.onreadystatechange = null;//移除`readystatechange`事件处理器
callback();
}else {//其他浏览器
script.onload = function() {
callback();
}
}
script.src = url;
document.head.appendChild(script);
}
}
}
如果需要的话,你可以动态加载尽可能多的JS文件到页面。但是:要考虑清楚文件的加载顺序。在所有主流浏览器中,只有Firefox和Opera能保证脚本会按照你指定的顺序执行,其他浏览器将会按照从服务器返回的顺序下载和执行代码。
对于多个文件,更好的做法还是把它们合并为一个文件。
XHR脚本注入是另一种无阻塞脚本加载方法。
let xhr = new XMLHttpRequest();
xhr.open("get","1.js",true);
xhr.onreadystatechange = function() {
if(xhr.readyState === 4) {
if(xhr.status => 200 && xhr.status < 300 || xhr.status === 304) {
let script = document.createElement("script");
script.text = xhr.responseText;
document.head.appendChild(script);
}
}
}
优点:你可以下载JS代码但不立即执行。由于代码是在script标签之外返回的,因此它下载后不会自动执行,这使得你可以把脚本的执行 推迟到你准备好的时候。
大型Web应用通常不会采用XHR脚本注入方式。
本篇对javascript脚本优化的介绍先暂时到这里,下一篇中我们将从作用域方面继续介绍。