HTML5中defer和async的深入对比

在网站页面中,通常需要引入外部js资源,然而外部的js资源可能导致DOM阻塞,影响页面加载速度。通过异步或者延迟执行js,可以做到引用外部js资源而不阻塞DOM的目的。用法是直接在script标签中使用defer和async,那么它们两个有什么区别呢?

从字面上来理解,defer是延迟,而async则是异步(Asynchronous)。w3c上这样解释defer和async:defer属性是一个布尔值的属性,当存在这个属性时,它指定的脚本将在页面解析之后执行1; async也是一个布尔值的属性,当存在这个属性时, 只要脚本是可用的它将异步执行2。更详细的可见火狐开发者中心对script标签的讲解。

概念的东西让人很难琢磨,下面是我对使用不同属性的外部引用标签的一个实验, 用php模拟一个外部javascript脚本:

<?php
header("Content-Type:text/javascript;charset=utf-8;");
sleep(2);
?>
console.log("This is the Script");
前台页面代码如下:

<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<script src="./js.php" defer></script>
<!-- 对上面的引入脚本分别进行defer和async的测试-->
<body>
This is The Document. 
</body>
</html>

下面的两张图片分别是使用defer和async的时间线:

使用defer的时间线

注意那条蓝色的时间线是DOMContentloaded时间,可以看到使用defer的DOMContentloaded事件是在JS脚本执行完之后,而使用async则是在html文档被解析完之后,相同之处是打印出”This is the Script”的时间一样。为什么会这样呢?

我们知道,如果javascript引入脚本既不使用defer也不使用async,整个页面是必须在引入脚本下载执行完毕之后才能继续被加载。而根据前面的概念,defer是延迟执行,async是异步执行。它们之间最大的区别是defer的执行时间是html文档被解析完成之后,而async的执行时间是不确定的,只要脚本被下载完毕,就会执行;它们之间的相同点是不会阻塞其它元素的加载。如果一个页面中有多个使用defer属性的外部脚本, 他们会按照顺序依次执行。

defer和async的应用

由于defer会在页面解析完成之后执行,所以当js脚本运行的时候,页面已经是解析完毕了的状态,这时候已经可以进行DOM操作, 而如果不使用defer,文档的状态不确定,所以不能进行操作。如上面的代码中,如果把js.php改成如下代码,打开前面页面,发现内容会被更改:

<?php
header("Content-Type:text/javascript;charset=utf-8;");
sleep(2);
?>
document.body.innerHTML="Body Content Has Been changed";
使用defer需要注意的是,由于defer的执行时机是页面解析完之后,含有defer的外部脚本执行时间是优先于内嵌脚本的,如下,内嵌脚本中放入一个DOMContentloaded的事件监听:

<!DOCTYPE HTML>
<html>
<head>
 <meta charset="UTF-8">
    <script>
        document.addEventListener("DOMContentLoaded",function(){
            console.log("内部脚本,DOMContentloaded发生!");
        },false);
    </script>>
    <script src="./js.js" defer></script>
    <!--外部脚本内容: console.log("外部脚本, 加载完毕!");-->
<body>
This is The Document. 
</body>
</html>
发现外部脚本内容先被打印出来。

而对于使用async的外部脚本来说,是在javascript文件被完全加载之后马上执行, 所以它可能会在DOM加载好之前被执行,也可能会在之后执行。这里的问题就是,如果异步加载的JS在DOM准备好之后执行,那么操作DOM的动作势必执行不了,如果在DOM准备好之前执行,则无法监听DOMContentloaded事件, 而依赖DOMContentloaded的事件回调就无法启动。例如一个HTML页面加入如下异步脚本代码:

<?php
header("Content-Type:text/javascript");
sleep(5);
?>
document.addEventListener("load",function(){
    console.log('DOMContentLoaded Event');
},false);

发现”DOMContentLoaded Event”无法打印,而去掉async属性后,就会正常打印”DOMContentLoaded Event”, 这说明在异步加载后,外部脚本执行的时候,DOMContentLoaded事件已经过去。

综上,defer和async最大的区别是执行时间的不同,defer实在DOM解析完毕之后马上执行,而async是在脚本下载完毕之后马上执行。执行时机的不同造成最终的效果各不相同,在实际中要小心对待。

时间: 2024-10-03 10:50:07

HTML5中defer和async的深入对比的相关文章

关于Javascript中defer和async的区别总结_javascript技巧

首先来看看这三句话: <script src="script.js"></script> 没有 defer 或 async,浏览器会立即加载并执行指定的脚本,"立即"指的是在渲染该 script 标签之下的文档元素之前,也就是说不等待后续载入的文档元素,读到就加载并执行. <script async src="script.js"></script> 有 async,加载和渲染后续文档元素的过程将和

浅析script标签中的defer与async属性_javascript技巧

一.前言 看到的前辈写的代码如下 <script src="#link("xxxx/xx/home/home.js")" type="text/javascript" async defer></script> 竟然同时有async和defer属性,心想着肯定是前辈老司机的什么黑科技,两个一块儿肯定会发生什么神奇化学反应,于是赶紧怀着一颗崇敬的心去翻书翻文档,先复习一下各自的定义. 二.调查一番 先看看async和defe

JS中script标签defer和async属性的区别详解_javascript技巧

向html页面中插入javascript代码的主要方法就是通过script标签.其中包括两种形式,第一种直接在script标签之间插入js代码,第二种即是通过src属性引入外部js文件.由于解释器在解析执行js代码期间会阻塞页面其余部分的渲染,对于存在大量js代码的页面来说会导致浏览器出现长时间的空白和延迟,为了避免这个问题,建议把全部的js引用放在</body>标签之前. script标签存在两个属性,defer和async,因此script标签的使用分为三种情况: 1.<script

常用的script标签:defer和async

文章简介:我们常用的script标签,有两个和性能.js文件下载执行相关的属性:defer和async. 我们常用的script标签,有两个和性能.js文件下载执行相关的属性:defer和async defer的含义[摘自https://developer.mozilla.org/En/HTML/Element/Script] This Boolean attribute is set to indicate to a browser that the script is meant to be

浏览器环境下JavaScript脚本加载与执行探析之defer与async特性_javascript技巧

defer和async特性相信是很多JavaScript开发者"熟悉而又不熟悉"的两个特性,从字面上来看,二者的功能很好理解,分别是"延迟脚本"和"异步脚本"的作用.然而,以defer为例,一些细节问题可能开发者却并不一定熟悉,比如:有了defer特性的脚本会延迟到什么时候执行:内部脚本和外部脚本是不是都能够支持defer:defer后的脚本除了会延迟执行之外,还有哪些特殊的地方等等.本文结合已有的一些文章以及MDN文档中对两个特性的阐述,对de

js的[defer]和[async]属性_javascript技巧

[defer] 可以在<script>中加入defer属性,告诉浏览器这段script不必立即执行,那么浏览器就会在完全载入文档之后再执行这个script,相当于window.onload,但它比window.onload更灵活. 复制代码 代码如下:  <script defer="true"></script> [async] 使用async属性加载JavaScript,这样整个脚本就可以异步加载和执行. <script>标签的def

HTML5中的Range对象的研究

一:Range对象的概念  Range对象代表页面上的一段连续区域,通过Range对象,可以获取或修改页面上的任何区域,可以通过如下创建一个空的Range对象,如下:       var  range = document.createRange(); 在html5中,每一个浏览器窗口及每一个窗口中都有一个selection对象,代表用户鼠标在页面中所选取的区域,(注意:经过测试IE9以下的浏览器不支持Selection对象), 可以通过如下语句创建selection对象:    var  se

html5中article标签的讲解

<article> 标签是用来定义一些来自外部的内容.比如一些网友的投稿或是新闻记者的文章或是摘取某博客.论坛的信息,以及其他媒介资料. 用户看到的内容并不是对应本网站的一个具体的页面,<article>是可以嵌套使用的,内外层内容相关联 示例代码: <html><body><article><h5>HTML5 项目</h5><p>HTML5是用于修正现在html的下一个网页规范</p><p&

html5中source标签的学习

source标签在html5中的作用是定义媒介源,比如<video>和<audio>定义媒介资源.这最新的HTML5标签是用来允许你指定视频和音频的文件. 示例代码: <video controls> <source="video.WMV" type="video/WMV" /> <!-MP4 for Mozilla Firefox --> <source="video.ogg"