关于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 相关文章推荐
Jquery 模拟用户点击超链接或者按钮的方法
Oct 25 Javascript
javascript内存管理详细解析
Nov 11 Javascript
JavaScript中Cookies的相关使用教程
Jun 04 Javascript
在Node.js应用中使用Redis的方法简介
Jun 24 Javascript
JS实现放大、缩小及拖拽图片的方法【可兼容IE、火狐】
Aug 23 Javascript
js前端面试题及答案整理(一)
Aug 26 Javascript
node.js中module.exports与exports用法上的区别
Sep 02 Javascript
静态页面实现 include 引入公用代码的示例
Sep 25 Javascript
详谈构造函数加括号与不加括号的区别
Oct 26 Javascript
AngularJs点击状态值改变背景色的实例
Dec 18 Javascript
使用vue-aplayer插件时出现的问题的解决
Mar 02 Javascript
jQuery对底部导航进行跳转并高亮显示的实例代码
Apr 23 jQuery
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 中dirname(_file_)讲解
2007/03/18 PHP
php读取目录及子目录下所有文件名的方法
2014/10/20 PHP
PHP中使用匿名函数操作数据库的例子
2014/11/17 PHP
PHP上传文件时自动分配路径的方法
2015/01/09 PHP
PHP实现自动识别原编码并对字符串进行编码转换的方法
2016/07/13 PHP
Javascript-Mozilla和IE中的一个函数直接量的问题
2007/01/09 Javascript
JS测试显示屏分辨率以及屏幕尺寸的方法
2013/11/22 Javascript
提高NodeJS中SSL服务的性能
2014/07/15 NodeJs
iPhone手机上搭建nodejs服务器步骤方法
2015/07/06 NodeJs
详解JavaScript编程中正则表达式的使用
2015/10/25 Javascript
jquery UI Datepicker时间控件的使用方法(加强版)
2015/11/07 Javascript
jQuery+css3实现转动的正方形效果(附demo源码下载)
2016/01/27 Javascript
jquery滚动条插件(可以自定义)
2016/12/11 Javascript
微信小程序 登录的简单实现
2017/04/19 Javascript
vue.js分页中单击页码更换页面内容的方法(配合spring springmvc)
2018/02/10 Javascript
从零开始搭建vue移动端项目到上线的步骤
2018/10/15 Javascript
微信小程序进入广告实现代码实例
2019/09/19 Javascript
解决layui页面按钮点击无反应,也不报错的问题
2019/09/29 Javascript
vue自动化路由的实现代码
2019/09/30 Javascript
在Vue中使用antv的示例代码
2020/06/29 Javascript
Python实例之wxpython中Frame使用方法
2014/06/09 Python
Python中getpass模块无回显输入源码解析
2018/01/11 Python
Python爬虫包BeautifulSoup简介与安装(一)
2018/06/17 Python
Python面向对象之类和对象实例详解
2018/12/10 Python
详解Python locals()的陷阱
2019/03/26 Python
python查看数据类型的方法
2019/10/12 Python
django 数据库 get_or_create函数返回值是tuple的问题
2020/05/15 Python
Django REST 异常处理详解
2020/07/15 Python
Pycharm中使用git进行合作开发的教程详解
2020/11/17 Python
谷歌浏览器小字体处理方案即12px以下字体
2013/12/17 HTML / CSS
HTML5 Canvas 实现K线图的示例代码
2019/12/23 HTML / CSS
Vrbo西班牙:预订您的度假公寓(公寓、乡村房屋…)
2020/04/27 全球购物
感恩老师的演讲稿
2014/05/06 职场文书
领导干部学习三严三实心得体会
2016/01/05 职场文书
浅谈Python类的单继承相关知识
2021/05/12 Python
《艾尔登法环》发布最新「战技」宣传片
2022/04/03 其他游戏