前端优化有一点就是优化js的执行时机,一般做法是将script放置于body的结束标签,以避免加载执行js 文件导致页面渲染阻塞的问题
这种做法确实能防止页面阻塞,但是在页面渲染完成之后才去加载js文件,有时候会显得js文件加载时间过长。
于是我们可以合理的使用script的属性defer,async

(一)分析defer,async的作用

(1)在不加defer,async的情况下
页面会预先渲染,如果遇到script 标签,他就会停止页面的继续渲染,去加载js文件,带文件加载完并执行结束之后,才会继续刚才暂停的页面渲染,
这意味着在head中加载的js文件如果有操作dom,或者获取dom节点信息的操作,可能会出错,因为DOMContentLoaded还没执行。
这也就是为什么需要将script文件放置在body结束标签之前的原因

(2)async
使用async之后会使得浏览器异步加载js文件,异步加载的意思是在加载js文件的过程中并不会阻塞页面的渲染,页面的渲染和js文件的加载是同时进行的
但是在js文件加载完之后,就会停止页面的渲染立即执行js文件,这个也是async与defer的区别。
如果在文件里面有相关dom操作可能会报错,因为html可能只是解析了一部分
因为带async的脚本一定会在load事件之前执行,可能会在DOMContentLoaded之前或之后执行,这个与加载脚本的时间长短有关系。

case 01

case 02

(3)defer
页面的渲染和js文件的加载是同时进行的,但是js文件加载完之后并不会立即执行而是需要在页面渲染完之后才去执行,但是带有defer的脚本(defer-script)是在DOMContentLoaded之前执行的

参考:https://html.spec.whatwg.org/multipage/scripting.html#ready-to-be-parser-executed

case 01

case 02

(二)区分load与DOMContentLoaded

DOMContentLoaded:
  当初始的 HTML 文档被完全加载和解析完成之后,DOMContentLoaded 事件被触发,而无需等待样式表、图像和子框架的完成加载。
  https://developer.mozilla.org/zh-CN/docs/Web/Events/DOMContentLoaded
load:
  当一个资源及其依赖资源已完成加载时,将触发load事件。
 
(三)HTML解析过程与DOMContentLoaded触发时机

1.在既没有CSS也没有JS的情况下,HTML文档的解析过程为

DOMContentLoaded事件的触发时机为:HTML解析为DOM之后。

2.有CSS无JS的情况下,HTML文档解析过程为:

这里与1.不同的地方在于,渲染树的生成是基于DOM和CSSOM的。但是触发DOMContentLoaded的时间依然是在HTML解析为DOM后,无论此时CSS解析为CSSOM的过程是否完成。

3.当有JS时,HTML文档解析过程为:

 

(四)JS单线程,浏览器多线程的问题

浏览器是多线程:
1.js引擎线程
  作用:JS内核,主要负责处理Javascript脚本程序,例如V8引擎。Javascript引擎线程理所当然是负责解析Javascript脚本,运行代码。
  js 是单线程(js引擎线程):
  js运作在浏览器中,是单线程的,js代码始终在一个线程上执行,因此任务分为同步(立即执行)异步任务(事件队列),
  web worker也只是允许JavaScript脚本创建多个线程,但是子线程完全受主线程控制,且不得操作DOM。

2.GUI渲染线程
  作用:渲染页面(js可以操作dom,影响渲染,所以js引擎线程和UI线程是互斥的。js执行时会阻塞页面的渲染)
  当界面需要重绘(Repaint)或由于某种操作引发回流(reflow)时,该线程就会执行
  GUI渲染线程与JS引擎是互斥的,当JS引擎执行时GUI线程会被挂起,GUI更新会被保存在一个队列中等到JS引擎空闲时立即被执行
  这也是为什么<script>标签要放到body标签的最底部。

3.浏览器事件触发线程
  作用:控制交互,响应用户
  当一个事件被触发时该线程会把事件添加到待处理队列的队尾,等待JS引擎的处理

4.http请求线程
  作用:ajax请求等
  在XMLHttpRequest在连接后是通过浏览器新开一个线程请求, 将检测到状态变更时,如果设置有回调函数,异步线程就产生状
  态变更事件放到 JavaScript引擎的处理队列中等待处理。在发起了一个异步请求时,http请求线程则负责去请求服务器,有了响应以后,
  事件触发线程再把回到函数放到事件队列当中。

5.定时触发器线程
  作用:setTimeout和setInteval

6.事件轮询处理线程
  作用:轮询消息队列,event loop

主线程执行的说明: 【js的运行机制】
(1)所有同步任务都在主线程上执行,形成一个执行栈。
(2)主线程之外,还存在一个”任务队列”。只要异步任务有了运行结果,就在”任务队列”之中放置一个事件。
(3)一旦”执行栈”中的所有同步任务执行完毕,系统就会读取”任务队列”,看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。
(4)主线程不断重复上面的第三步。

参考链接:https://blog.csdn.net/github_34514750/article/details/76577663

script 标签的defer,async的作用,及拓展浏览器多线程,DOMContentLoaded的更多相关文章

  1. HTML <script> 标签的 defer 和 async 属性

    HTMKL <script>标签中有defer和async属性,简单介绍一下两者的区别吧.   普通的script标签会让浏览器立即下载并执行完毕,执行也是按照先后顺序,再进行后面的解析. ...

  2. script标签的defer、async属性

    之前一直对script标签的defer.async属性一知半解,直到看到了论坛上某大神发的图片,茅塞顿开!!!!!

  3. 怎样理解script标签的defer属性和async属性

    如果script标签是引用的外部js文件, 那就会有一个下载js文件这一过程, 为了不因为这个下载过程而阻塞页面解析与渲染, 我们需要一种机制来解决这一问题, 方法之一就是使用 defer和async ...

  4. script标签中defer和async属性的区别

    这篇文章来源于JS高级程序设计第三版中关于script标签的介绍,结合查阅的资料写下的学习笔记. 向html页面中插入javascript代码的主要方法就是通过script标签.其中包括两种形式,第一 ...

  5. 浅谈script标签中的async和defer

    script标签用于加载脚本与执行脚本,在前端开发中可以说是非常重要的标签了.直接使用script脚本的话,html会按照顺序来加载并执行脚本,在脚本加载&执行的过程中,会阻塞后续的DOM渲染 ...

  6. script标签中的async、defer属性

    Script标签是我们常用的引用js脚本的一种方式. 撸代码的时候,我们常常只写src属性,直接忽略其他属性. 最近发现了2个可以利用的属性:async.defer. 顾名思义async就是异步,在不 ...

  7. script标签中defer和async的区别(稀土掘金学习)

    如果没有defer或async属性,浏览器会立即加载并执行相应的脚本.它不会等待后续加载的文档元素,读取到就会开始加载和执行,这样就阻塞了后续文档的加载. 下图可以直观的看出三者之间的区别: 其中蓝色 ...

  8. script 标签里的 async 和 defer

    无 async 和 defer 浏览器立即加载并执行指定脚本(读到即加载并执行),阻塞文档解析 async 脚本的加载执行和文档的加载渲染 并行. defer 脚本的加载和文档的加载渲染并行,但脚本的 ...

  9. <script>标签里的defer和async属性 区别(待补充)

    defer与async的区别(表格显示): table th:first-of-type { width: 150px; } table th:nth-of-type(2) { } 区别 defer ...

随机推荐

  1. html5- 摘自网友dudu

    HTML5中新增了<canvas>画布标签,通过它,可以使用JavaScript在网页中绘制图像.<canvas>标签在网页中得到的是一个矩形空白区域,可以通过width和he ...

  2. OC BLOCK和协议

    一.BOLCK (一)简介 BLOCK是什么?苹果推荐的类型,效率高,在运行中保存代码.用来封装和保存代码,有点像函数,BLOCK可以在任何时候执行. block实际上是: 指向结构体的指针 BOLC ...

  3. SQL调优(SQL TUNING)之远程支持完成性能大幅优化

    前几天,一个朋友找到我,说一个SQL性能有问题,看看能不能优化,下面为过程: 雪豹 9:35:10 在吗 兰花岛主 15:07:39 忙忘了,有事儿? 雪豹 15:07:49 嗯 雪豹 15:07:5 ...

  4. css实现椭圆

    先实现个简单点的,用css实现一个圆,ok,直接上代码: .circle{ width: 100px; height:100px; background: red; border-radius: 50 ...

  5. RabbitMQ整合spring

    <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.sp ...

  6. BZOJ3544 [ONTAK2010]Creative Accounting

    看不懂题,就不能写的稍微像人话点吗我去... 题目就是要找一段区间使得Σai mod m的值最大. 于是嘛...前缀和一下再贪心就好了. 先求出前i个数的前缀和s,然后用s更新解. 还有可能就是前面的 ...

  7. Java实现交换两个String

    在Java中我们所使用的实例变量其实都是一个引用,所以如果要求实现一个swap(String A, String B)这种函数时无法实现的,因为在类方法的定义中是先对行参进行地址传递,然后对形参修改, ...

  8. java程序员常用的八个工具

    以下这8个工具,从代码构建到错误挤压,覆盖Java开发的全域.学习这些工具可以帮助你改善代码质量,成为一个更高效的Java开发人员. 1.Eclipse 尽管IntelliJ IDEA.NetBean ...

  9. Eclipse中SVN的安装步骤(两种)和使用方法

    Eclipse中SVN的安装步骤(两种)和使用方法 一.给Eclipse安装SVN,最常见的有两种方式:手动方式和使用安装向导方式.具体步骤如下: 方式一:手动安装 1.下载最新的Eclipse,我的 ...

  10. TimeSpan格式化字符串格式(摘)

    一直在用DateTime, 却不常用TimeSpan , 今天突然用到了, 发现不知道咋做格式化...百度一下,找到了答案, 在这记录一下, 免得以后找花费时间 以下内容摘抄自 Microsoft D ...