泰州商城网站开发,校园门户网站系统建设关键技术,网站建设推广型,如何查看网站服务器时间上一篇刚转载了一篇有关于网站性能优化的文章#xff0c;其中提及到了页面的加载和渲染的过程#xff0c;提到了defer和async的相关区别#xff0c;但是本人在此之前并没有深究其中的区别。
defer和async是script标签的两个属性#xff0c;用于在不阻塞页面文档解析的前提…上一篇刚转载了一篇有关于网站性能优化的文章其中提及到了页面的加载和渲染的过程提到了defer和async的相关区别但是本人在此之前并没有深究其中的区别。
defer和async是script标签的两个属性用于在不阻塞页面文档解析的前提下控制脚本的下载和执行。 在介绍他们之前我们有必要先了解一下页面的加载和渲染过程
列表内容浏览器通过HTTP协议请求服务器获取HMTL文档并开始从上到下解析构建DOM 在构建DOM过程中如果遇到外联的样式声明和脚本声明则暂停文档解析创建新的网络连接并开始下载样式文件和脚本文件 样式文件下载完成后构建CSSDOM脚本文件下载完成后解释并执行然后继续解析文档构建DOM 完成文档解析后将DOM和CSSDOM进行关联和映射最后将视图渲染到浏览器窗口
在这个过程中脚本文件的下载和执行是与文档解析同步进行也就是说它会阻塞文档的解析如果控制得不好在用户体验上就会造成一定程度的影响。
所以我们需要清楚的了解和使用defer和async来控制外部脚本的执行。
先来简明概要的介绍一下下面三者的区别
script srcscript.js/script 没有 defer 或 async浏览器会立即加载并执行指定的脚本“立即”指的是在渲染该 script 标签之下的文档元素之前也就是说不等待后续载入的文档元素读到就加载并执行。script async srcscript.js/script 有 async加载和渲染后续文档元素的过程将和 script.js 的加载与执行并行进行异步script defer srcmyscript.js/script 有 defer加载后续文档元素的过程将和 script.js 的加载并行进行异步但是 script.js 的执行要在所有元素解析完成之后DOMContentLoaded 事件触发之前完成。
接着我们来看一张图
蓝色线代表网络读取红色线代表执行时间这俩都是针对脚本的绿色线代表 HTML 解析。
此图告诉我们以下几个要点
defer 和 async 在网络读取下载这块儿是一样的都是异步的相较于 HTML 解析它俩的差别在于脚本下载完之后何时执行显然 defer 是最接近我们对于应用脚本加载和执行的要求的关于 defer此图未尽之处在于它是按照加载顺序执行脚本的这一点要善加利用async 则是一个乱序执行的主反正对它来说脚本的加载和执行是紧紧挨着的所以不管你声明的顺序如何只要它加载完了就会立刻执行仔细想想async 对于应用脚本的用处不大因为它完全不考虑依赖哪怕是最低级的顺序执行不过它对于那些可以不依赖任何脚本或不被任何脚本依赖的脚本来说却是非常合适的最典型的例子Google Analytics
下面为了演示脚本的执行情况借鉴了详解defer和async原理及应用 为了演示脚本的执行情况进而介绍这两个属性的作用我们先来搭建一个简单的服务器 创建了一个简易的Node服务器server.js其代码如下
var http require(http);
var fs require(fs);var typeMapping {html: text/html,js : text/javascript,css : text/css,ico : image/x-icon
};var getResourceExtension function(req) {var url req.url;var lastIndexOfDot url.lastIndexOf(.);if (lastIndexOfDot -1) return text/plain;return url.substring(lastIndexOfDot 1);
};var respondResourceToClient function(req, res) {//read the reource and respond via pipefs.createReadStream(req.url.replace(/^\//, )).pipe(res);
};var server http.createServer(function(req, res) {console.log(requesting url: , req.url);var extension getResourceExtension(req);res.writeHead(200, {Content-Type: typeMapping[extension]});var delay function(time) {setTimeout(function() {respondResourceToClient(req, res);}, time || 0);};if (extension html || extension css) {delay(0);} else if (extension js) {delay(1000);} else {res.end();}
});server.listen(3000);console.log(listening at port 3000...);
从上面的代码我们可以看出当服务器接收到请求之后会判断请求资源是否为JS如果是则延迟1s后返回对应的资源。 启动这个服务很简单只需执行node server.js即可然后就可以在浏览器中输入http://localhost:3000/app/index.html访问主页了 现在我们来看看index.html中的内容
!DOCTYPE html
htmlheadtitledefer async/titlelink relstylesheet typetext/css hrefcss/main.cssscript typetext/javascript srcjs/1.js/script/headbodydiv classtextHello World/divscript typetext/javascript srcjs/2.js/script/body
/html
在这个HTML文档中我们先在head中引用了一个外部的脚本文件js/1.js然后在我们要显示的Hello World后面又引用了一个js/2.js它们的内容都很简单就是弹出对应的标示信息
// js/1.js
alert(1);// js/2.js
alert(2);
下面我们就来访问主页看看会发生些什么
从图中可以看到渲染的过程的确是自上而下同步进行的也就是说遇到外部的脚本就得暂停文档的解析下载并且解释执行这种方式是阻塞的会造成网页空白的现象。
现在稍微修改一下代码将head中的script标签加上defer属性然后也稍微改动一下两个JS文件
!DOCTYPE html
htmlheadtitledefer async/titlelink relstylesheet typetext/css hrefcss/main.css!-- adding a defer attribute, by default, the value will be true --script typetext/javascript srcjs/1.js defer/script/headbodydiv classtextHello World/divscript typetext/javascript srcjs/2.js/script/body
/html
// js/1.js
console.log(1);// js/2.js
console.log(2);
再次访问index.html我们会在控制台中看到下面的执行顺序
显而易见1.js被延后致至文档解析完成后执行了它的执行顺序比body中的
!DOCTYPE html
htmlheadtitledefer async/titlelink relstylesheet typetext/css hrefcss/main.css!-- adding a defer attribute, by default, the value will be true --script typetext/javascript srcjs/1.js defer/scriptscript typetext/javascript srcjs/2.js defer/scriptscript typetext/javascript deferconsole.log(3);/script/headbodydiv classtextHello World/divscript typetext/javascriptdocument.addEventListener(DOMContentLoaded, function() {console.log(dom content loaded, ready state:, this.readyState);}, false);window.addEventListener(load, function() {console.log(window loaded, dom ready state:, document.readyState);}, false);/script/body
/html 可以看到外联的脚本是按照声明顺序执行的内联脚本并没有遵守这个规则另外DOMContentLoaded和load事件依次被捕获DOM的状态分别变为interactive和complete
接下来我们介绍一下async属性为了能够很好的演示执行顺序我们还需要一些修改
!DOCTYPE html
htmlheadtitledefer async/titlelink relstylesheet typetext/css hrefcss/main.css!-- adding a async attribute, by default, the value is true as well --script typetext/javascript srcjs/1.js async/scriptscript typetext/javascript srcjs/2.js async/scriptscript typetext/javascript srcjs/3.js async/script/headbodydiv classtextHello World/div/body
/html
JS文件内如下
// js/1.js
console.log(1);// js/2.js
console.log(2);// js/3.js
console.log(3);
再次访问index.html会发现控制台打印如下
我们发现3个脚本的执行是没有顺序的我们也无法预测每个脚本的下载和执行的时间和顺序。async和defer一样不会阻塞当前文档的解析它会异步地下载脚本但和defer不同的是async会在脚本下载完成后立即执行如果项目中脚本之间存在依赖关系不推荐使用async。
关于async也需要注意以下几点 1. 只适用于外联脚本这一点和defer一致 2. 如果有多个声明了async的脚本其下载和执行也是异步的不能确保彼此的先后顺序 3. async会在load事件之前执行但并不能确保与DOMContentLoaded的执行先后顺序
以上就是defer和async的介绍了解和掌握这两个属性的作用不仅对JS代码执行的控制更加熟练也会对页面渲染多一分了解。
参考文章
http://blog.csdn.net/liuhe688/article/details/51247484https://segmentfault.com/q/1010000000640869