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


Posted in Javascript onSeptember 20, 2016

首先来看看这三句话:

<script src="script.js"></script>

没有 defer 或 async,浏览器会立即加载并执行指定的脚本,“立即”指的是在渲染该 script 标签之下的文档元素之前,也就是说不等待后续载入的文档元素,读到就加载并执行。

<script async src="script.js"></script>

有 async,加载和渲染后续文档元素的过程将和 script.js 的加载与执行并行进行(异步)。

<script defer src="myscript.js"></script>

有 defer,加载后续文档元素的过程将和 script.js 的加载并行进行(异步),但是 script.js 的执行要在所有元素解析完成之后,DOMContentLoaded 事件触发之前完成。

下面来进行详解的介绍这二者的区别。

一般情况

按照惯例,所有script元素都应该放在页面的head元素中。这种做法的目的就是把所有外部文件(CSS文件和JavaScript文件)的引用都放在相同的地方。可是,在文档的head元素中包含所有JavaScript文件,意味着必须等到全部JavaScript代码都被下载、解析和执行完成以后,才能开始呈现页面的内容(浏览器在遇到body标签时才开始呈现内容)。

对于那些需要很多JavaScript代码的页面来说,这无疑会导致浏览器在呈现页面时出现明显的延迟,而延迟期间的浏览器窗口中将是一片空白。为了避免这个问题,现在Web应用程序一般都全部JavaScript引用放在body元素中页面的内容后面。这样一来,在解析包含的JavaScript代码之前,页面的内容将完全呈现在浏览器中。而用户也会因为浏览器窗口显示空白页面的时间缩短而感到打开页面的速度加快了。

<!DOCTYPE html>
<html>
<head>
 <meta charset="utf-8">
 <meta http-equiv="X-UA-Compatible" content="IE=edge">
 <title></title>
</head>
<body>
<script type="text/javascript" src="script.js"></script>
</body>
</html>

defer (延迟脚本)

延迟脚本:defer属性只适用于外部脚本文件。

如果给script标签定义了defer属性,这个属性的作用是表明脚本在执行时不会影响页面的构造。也就是说,脚本会被延迟到整个页面都解析完毕后再运行。因此,如果script元素中设置了defer属性,相当于告诉浏览器立即下载,但延迟执行。

示例:

<!DOCTYPE html>
<html>
<head>
 <meta charset="utf-8">
 <meta http-equiv="X-UA-Compatible" content="IE=edge">
 <title>延迟加载</title>
 <script defer type="text/javascript" src="test.js"></script>
</head>
<body>
</body>
</html>

这个例子中,虽然我们把script元素放在了文档的head元素中,但其中包含的脚本将延迟到浏览器遇到</html>标签后再执行
HTML5规范要求脚本按照它们出现的先后顺序执行,因此第一个延迟脚本会先于第二个延迟脚本执行,而这两个脚本会先于DOMContentLoaded事件(在DOM树构建完成后触发,不需要等到所有的资源都加载完毕)执行。

特别注意:在现实当中,延迟脚本并不一定会按照顺序执行,也不一定会在DOMContentLoaded事件触发前执行,因此最好只包含一个延迟脚本。

有 defer,加载后续文档元素的过程将和 script.js 的加载并行进行(异步),但是 script.js 的执行要在所有元素解析完成之后,DOMContentLoaded 事件触发之前完成。

最佳实践

从实用角度来说,把所有脚本都放在 </body> 之前是最佳实践,因为对于旧浏览器来说这是唯一的优化选择,此法可保证非脚本的其他一切元素能够以最快的速度得到加载和解析。

**注意:**defer属性在浏览器之间表现并不一致。为了避免跨浏览器的差异,可以使用 “lazy loading”的方法,即直到用到该脚本时才加载。

function lazyload() {
 var elem = document.createElement("script");
 elem.type = "text/javascript";
 elem.async = true;
 elem.src = "script.js"; 
 document.body.appendChild(elem);
}

if (window.addEventListener) {
 window.addEventListener("load", lazyload, false);
} else if (window.attachEvent) {
 window.attachEvent("onload", lazyload);
} else {
 window.onload = lazyload;
}

async(异步脚本)

异步脚本:async属性也只适用于外部脚本文件,并告诉浏览器立即下载文件。

但与defer不同的是:标记为async的脚本并不保证按照指定它们的先后顺序执行。

<!DOCTYPE html>
<html>
<head>
 <meta charset="utf-8">
 <meta http-equiv="X-UA-Compatible" content="IE=edge">
 <title>异步加载</title>
 <script async type="text/javascript" src="test1.js"></script>
 <script async type="text/javascript" src="test2.js"></script>
</head>
<body>
</body>
</html>

这个例子中,test2.js可能会在test1.js之前执行。因此,确保两者之间互不一来非常重要。指定async属性的目的是不让页面等待两个脚本下载和执行,从而异步加载页面其他内容。因此,建议异步脚本不要在加载期间修改DOM。

来看一张更加清晰的图:

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

图解:蓝色线代表网络读取,红色线代表执行时间,这两个都是针对脚本的;绿色线代表 HTML 解析。

通过上图和之前的分析,我们可以得出:

      1、defer 和 async 在网络读取(脚本下载)这块儿是一样的,都是异步的(相较于 HTML 解析)

      2、两者的差别:在于脚本下载完之后何时执行,显然 defer 是最接近我们对于应用脚本加载和执行的要求的。defer是立即下载但延迟执行,加载后续文档元素的过程将和脚本的加载并行进行(异步),但是脚本的执行要在所有元素解析完成之后,DOMContentLoaded 事件触发之前完成。async是立即下载并执行,加载和渲染后续文档元素的过程将和js脚本的加载与执行并行进行(异步)。

      3、关于 defer,我们还要记住的是它是按照加载顺序执行脚本的

      4、标记为async的脚本并不保证按照指定它们的先后顺序执行。对它来说脚本的加载和执行是紧紧挨着的,所以不管你声明的顺序如何,只要它加载完了就会立刻执行。

      5、async 对于应用脚本的用处不大,因为它完全不考虑依赖(哪怕是最低级的顺序执行),不过它对于那些可以不依赖任何脚本或不被任何脚本依赖的脚本来说却是非常合适的。

总结

以上就是关于js中defer和async区别的全部内容,文章介绍的很详细,希望能对大家的学习或者工作带来一定的帮助,如果有疑问大家可以留言交流。

Javascript 相关文章推荐
javascript 页面划词搜索JS
Sep 28 Javascript
js 兼容多浏览器的回车和鼠标焦点事件代码(IE6/7/8,firefox,chrome)
Apr 14 Javascript
jQuery选中select控件 无法设置selected的解决方法
Sep 01 Javascript
jQuery之ajax技术的详细介绍
Jun 19 Javascript
仿谷歌主页js动画效果实现代码
Jul 14 Javascript
jQuery中closest()函数用法实例
Jan 07 Javascript
使用HTML+CSS+JS制作简单的网页菜单界面
Jul 27 Javascript
JS实现的页面自定义滚动条效果
Oct 26 Javascript
javascript HTML5文件上传FileReader API
Mar 27 Javascript
使用jQuery给input标签设置默认值
Jun 20 Javascript
IE8利用自带的setCapture和releaseCapture解决iframe的拖拽事件方法
Oct 25 Javascript
Ionic + Angular.js实现验证码倒计时功能的方法
Jun 12 Javascript
javascript数组对象常用api函数小结(连接,插入,删除,反转,排序等)
Sep 20 #Javascript
javascript字符串对象常用api函数小结(连接,替换,分割,转换等)
Sep 20 #Javascript
JQuery手速测试小游戏实现思路详解
Sep 20 #Javascript
javascript cookie基础应用之记录用户名的方法
Sep 20 #Javascript
深入理解requestAnimationFrame的动画循环
Sep 20 #Javascript
javascript cookie用法基础教程(概念,设置,读取及删除)
Sep 20 #Javascript
谈谈对JavaScript原生拖放的深入理解
Sep 20 #Javascript
You might like
PHP中json_encode、json_decode与serialize、unserialize的性能测试分析
2010/06/09 PHP
PHP多态代码实例
2015/06/26 PHP
WordPress中编写自定义存储字段的相关PHP函数解析
2015/12/25 PHP
PHP flush 函数使用注意事项
2016/08/26 PHP
PHP将身份证正反面两张照片合成一张图片的代码
2017/04/08 PHP
laravel实现批量更新多条记录的方法示例
2017/10/22 PHP
js event事件的传递与冒泡处理
2009/12/06 Javascript
jQuery解决input元素的blur事件和其他非表单元素的click事件冲突问题
2016/08/15 Javascript
JS搜狐面试题分析
2016/12/16 Javascript
Vue数据驱动模拟实现4
2017/01/12 Javascript
php register_shutdown_function函数详解
2017/07/23 Javascript
Vue网页html转换PDF(最低兼容ie10)的思路详解
2017/08/24 Javascript
cordova入门基础教程及使用中遇到的一些问题总结
2017/11/14 Javascript
JQuery实现table中tr上移下移的示例(超简单)
2018/01/08 jQuery
vue中echarts3.0自适应的方法
2018/02/26 Javascript
NodeJs实现简单的爬虫功能案例分析
2018/12/05 NodeJs
JS+php后台实现文件上传功能详解
2019/03/02 Javascript
Vue.js标签页组件使用方法详解
2019/10/19 Javascript
Python找出list中最常出现元素的方法
2016/06/14 Python
Python中的命令行参数解析工具之docopt详解
2017/03/27 Python
python文件操作之批量修改文件后缀名的方法
2018/08/10 Python
jupyter notebook的安装与使用详解
2020/05/18 Python
Python 实现将numpy中的nan和inf,nan替换成对应的均值
2020/06/08 Python
CSS3教程(1):什么是CSS3
2009/04/02 HTML / CSS
纯CSS3制作的简洁蓝白风格的登录模板(非IE效果更好)
2013/08/11 HTML / CSS
Forever 21美国官网:美国标志性快时尚品牌
2017/02/20 全球购物
美国马匹用品和马钉购物网站:State Line Tack
2018/08/05 全球购物
香港通票:Hong Kong Pass
2019/02/26 全球购物
Bed Bath & Beyond加拿大官网:购买床上用品、浴巾、厨房电器等
2019/10/04 全球购物
意大利比基尼品牌:MISS BIKINI
2019/11/02 全球购物
有影响力的人、名人和艺术家的官方商品:Represent
2019/11/26 全球购物
团队口号大全
2014/06/06 职场文书
大明湖导游词
2015/02/03 职场文书
学雷锋日活动总结
2015/02/06 职场文书
学校运动会加油词
2015/07/18 职场文书
灵能百分百第三季什么时候来?
2022/03/15 日漫