defer和async的区别

2021-03-05 09:25发布

8条回答
三岁奶猫
2楼 · 2021-03-05 13:16

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

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

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

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

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


有点好奇
3楼 · 2021-03-05 13:41

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

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

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

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

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


我的网名不再改
4楼 · 2021-03-05 16:10

defer和async是script标签的两个属性,用于在不阻塞页面文档解析的前提下,控制脚本的下载和执行。

在介绍他们之前,我们有必要先了解一下页面的加载和渲染过程:

1. 浏览器通过HTTP协议请求服务器,获取HMTL文档并开始从上到下解析,构建DOM;

2. 在构建DOM过程中,如果遇到外联的样式声明和脚本声明,则暂停文档解析,创建新的网络连接,并开始下载样式文件和脚本文件;

3. 样式文件下载完成后,构建CSSDOM;脚本文件下载完成后,解释并执行,然后继续解析文档构建DOM

4. 完成文档解析后,将DOM和CSSDOM进行关联和映射,最后将视图渲染到浏览器窗口

在这个过程中,脚本文件的下载和执行是与文档解析同步进行,也就是说,它会阻塞文档的解析,如果控制得不好,在用户体验上就会造成一定程度的影响。

所以我们需要清楚的了解和使用defer和async来控制外部脚本的执行。

在开发中我们可以在script中声明两个不太常见的属性:defer和async,下面分别解释了他们的用法:

defer:用于开启新的线程下载脚本文件,并使脚本在文档解析完成后执行。

async:HTML5新增属性,用于异步下载脚本文件,下载完毕立即解释执行代码。

为了演示脚本的执行情况,进而介绍这两个属性的作用,我们先来搭建一个简单的服务器:


如图所示,我们创建一个app目录,用于放置一些简单的Web资源,同时创建了一个简易的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 'pipe'

    fs.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中的内容:


   

        defer & async

       

        [removed][removed]

   

   

       

Hello World

        [removed][removed]

   


在这个HTML文档中,我们先在head中引用了一个外部的脚本文件js/1.js,然后在我们要显示的Hello World后面又引用了一个js/2.js,它们的内容都很简单,就是弹出对应的标示信息:


// js/1.js

alert(1);


// js/2.js

alert(2);


下面我们就来访问主页,看看会发生些什么:


从图中可以看到,渲染的过程的确是自上而下,同步进行的,也就是说遇到外部的脚本,就得暂停文档的解析,下载并且解释执行,这种方式是阻塞的,会造成网页空白的现象。

现在稍微修改一下代码,将head中的script标签加上defer属性,然后也稍微改动一下两个JS文件:


   

        defer & async

       

       

        [removed][removed]

   

   

       

Hello World

        [removed][removed]

   


// js/1.js

console.log(1);


// js/2.js

console.log(2);


再次访问index.html,我们会在控制台中看到下面的执行顺序:


显而易见,1.js被延后致至文档解析完成后执行了,它的执行顺序比body中的[removed]还要靠后。与默认的同步解析不同,defer下载外部脚本的不是阻塞的,浏览器会另外开启一个线程,进行网络连接下载,这个过程中,文档解析及构建DOM仍可以继续进行,不会出现因下载脚本而出现的页面空白。

关于defer我们需要注意下面几点:

1. defer只适用于外联脚本,如果script标签没有指定src属性,只是内联脚本,不要使用defer

2. 如果有多个声明了defer的脚本,则会按顺序下载和执行

3. defer脚本会在DOMContentLoaded和load事件之前执行

我们稍微改动一下代码,验证一下上面的几条:


   

        defer & async

       

       

        [removed][removed]

        [removed][removed]

        [removed]

            console.log(3);

        [removed]

   

   

       

Hello World


        [removed]

            document.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);

        [removed]

   


上面代码中,head中所有的script标签都加上了defer,其中第三个是内联脚本,然后我们也添加了DOMContentLoaded和load事件,下面来看一下打印的结果:


可以看到,外联的脚本是按照声明顺序执行的,内联脚本并没有遵守这个规则,另外,DOMContentLoaded和load事件依次被捕获,DOM的状态分别变为interactive和complete。


接下来我们介绍一下async属性,为了能够很好的演示执行顺序,我们还需要一些修改:


   

        defer & async

       

       

        [removed][removed]

        [removed][removed]

        [removed][removed]

   

   

       

Hello World

   


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的执行先后顺序


不吃鱼的猫
5楼 · 2021-03-06 10:11

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

我是大脸猫
6楼 · 2021-03-07 22:29

先来试个一句话解释仨,当浏览器碰到 script 脚本的时候:

  1. [removed][removed]

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

  2. [removed][removed]

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

  3. [removed][removed]

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

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

接着,我们来看一张图咯:

请输入图片描述

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

此图告诉我们以下几个要点:

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

  2. 它俩的差别在于脚本下载完之后何时执行,显然 defer 是最接近我们对于应用脚本加载和执行的要求的

  3. 关于 defer,此图未尽之处在于它是按照加载顺序执行脚本的,这一点要善加利用

  4. async 则是一个乱序执行的主,反正对它来说脚本的加载和执行是紧紧挨着的,所以不管你声明的顺序如何,只要它加载完了就会立刻执行

  5. 仔细想想,async 对于应用脚本的用处不大,因为它完全不考虑依赖(哪怕是最低级的顺序执行),不过它对于那些可以不依赖任何脚本或不被任何脚本依赖的脚本来说却是非常合适的,最典型的例子:Google Analytics


天才小馒头
7楼 · 2021-03-08 15:41

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

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

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

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

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

灰机带翅膀
8楼 · 2021-03-12 10:05

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

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

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

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

2、它俩的差别在于脚本下载完之后何时执行,显然 defer 是最接近我们对于应用脚本加载和执行的要求的

3、关于 defer,此图未尽之处在于它是按照加载顺序执行脚本的,这一点要善加利用

4、async 则是一个乱序执行的主,反正对它来说脚本的加载和执行是紧紧挨着的,所以不管你声明的顺序如何,只要它加载完了就会立刻执行

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




征戰撩四汸
9楼 · 2022-05-07 15:40

deferasync的区别是:前者要等到整个页面正常渲染结束,才会执行;后者一旦下载完,渲染引擎就会中断渲染,执行这个脚本以后,再继续渲染。一句话,defer是“渲染完再执行”,async是“下载完就执行”。另外,如果有多个defer脚本,会按照它们在页面出现的顺序加载,而多个async脚本是不能保证加载顺序的。

相关问题推荐

  • 回答 120

    相对前几年来说,要高上不少了,毕竟入行的人也是越来越多了,基础的工作对应想要参与的人群基数越来越大,但是对于高端人才的需求还是很多,人才还是相对稀缺性的。所以,想要学web或者其他技术也一样,别等,别观望。web前端就业方向特别多包括web前端开发...

  • 回答 25

    相对定位和绝对定位是定位的两种表现形式,区别如下:一、主体不同1、相对定位:是设置为相对定位的元素框会偏移某个距离。2、绝对定位:absolute 脱离文档流,通过 top,bottom,left,right 定位。二、特点不同1、相对定位:在使用相对定位时,无论是否进行移...

  • 抓包是什么意思?2020-04-01 17:36
    回答 7
    已采纳

    抓包(packet capture)就是将网络传输发送与接收的数据包进行截获、重发、编辑、转存等操作,也用来检查网络安全。抓包也经常被用来进行数据截取等。抓包可以通过抓包工具来查看网络数据包内容。通过对抓获的数据包进行分析,可以得到有用的信息。目前流行的...

  • 回答 89

    常用的前端框架有Bootstrap框架、React框架、Vue框架、Angular框架、Foundation框架等等

  • 回答 65
    已采纳

    前端是目的就业前景非常不错的一个计算机技术,但是自学的话还是有一定难度的,网络上自学是碎片化的,同时互联网技术跟新换代快,自己的话比较吃力也学习不到最新的技术。

  • SSR 是什么意思?2020-03-20 18:56
    回答 6

    SSR就是一台服务器,可以利用 SSR 在远程的服务器上配置 SSR,使其能够成为 SSR 节点,这样本地电脑或者其它设备利用 SSR 节点实现 VPN 或者远程上网及游戏加速等方面。ShadowsocksR(简称 SSR)是 Shadowsocks 分支,在 Shadowsocks 的基础上增加了一些数据...

  • 回答 11

    1、代码判断xAxis: {type: 'time',splitLine: {show: false},interval: 3600, // 设置x轴时间间隔axisLabel: {formatter: function(value, index) {return liangTools.unix2hm(value)}}},首先要把xAxis 显示类型设置成time,然后设置对应X轴......

  • 回答 52
    已采纳

    计算机培训方向比较多,建议找适合自己的方向选择培训编程类:JAVA、WEB、Python、C/C++、C#等测试类:软件测试运维类:云计算、网络安全设计类:UI设计、3D建模等

  • 回答 8

    HTML5 + CSS + JavaScript 开发 跨平台重用代码 

  • 回答 4

    采用rem单位自动响应,并提供独有栅格化系统快速定义宽高、边距节省css代码量,同时总结各大型移动端网页,提供一套ui颜色搭配规范,尺寸规范,字体规范等。

  • 回答 10

    iView UI、ioni、SUI

  • 回答 6

     jQTouch 

  • 回答 4

    如果只是普通的移动端用vue react 或者dva 如果是要编译成小程序什么的或者混生 就用uni-app(对应vue语法)taro(对应react) 或者纯原生 这个没有限制的,自己怎么舒服怎么来

  • 回答 4

    因为可以运用在网页和小程序的开饭中,而且开源,用着便宜,企业都很喜欢

  • 回答 10

    一、Visual Studio Code下载地址:https://code.visualstudio.com/微软在2015年4月30日Build 开发者大会上正式宣布了 Visual Studio Code 项目:一个运行于 Mac OS X、Windows和 Linux 之上的,针对于编写现代 Web 和云应用的跨平台源代码编辑器。Visual Stud...

  • 回答 9

    jQuery自带淡入淡出效果 https://www.w3school.com.cn/jquery/jquery_fade.asp 看看这个 

没有解决我的问题,去提问