Script标签和脚本执行顺序

一文大白话讲清楚script加载和执行顺序,包括script标签、defer、async、动态script等 本文详细分析了script标签的加载和执行顺序,包括普通script标签、defer、async和动态script四种方式。普通script会阻塞HTML解析,按顺序执行;defer异步加载但保持顺序执行,在DOMContentLoaded前完成;async异步加载且立即执行,不保证顺序;动态script默认类似async,但设置async=false后可保证顺序执行。每种方式适用于不同场景,开发者应根据需求选择合适的方法来优化页面加载性能。 阅读详情

0.前言

估计所有读者也慢慢适应我每次讲东西之前先墨迹一段的习惯了。

那么我今天就来个转换,我!不!墨!迹!了!

正文开始。

1.script标签的默认行为


首先我们先来看一下 <script> 标签 的几个重要特性:

  • script标签的会阻止文档渲染。相关脚本会立即下载并执行。
    注意:(不带defer或async属性)
  • document.currentScript 可以获得当前正在运行的脚本(Chrome 29+, FF4+)。
  • 脚本顺序再默认情况下和script标签出现的顺序一致。

既然我们已经明确了 script 标签的基本特性。

那我们就先来看一个例子,用这个例子来说明 script 的加载顺序问题。

2. script 的加载顺序


假设如下简单代码,我们去看一下,执行的结果是什么样子?

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>李鹏:3206064928</title>
</head>
<body>

</body>
    <script>alert("MR_LP : A");</script>
    <script>alert("MR_LP : B");</script>
    <script>alert("MR_LP : C");</script>
</html>

执行结果如下:

这是我们按照正常的逻辑去执行,分别弹出了 :

  1. MR_LP : A
  2. MR_LP : B
  3. MR_LP : C

那我们再去考虑一下,在有网络的情况,请求的顺序会怎样呢?

在这里我去做一个限制,将我们的第二个文件中,书写非常多的注释,让我们的第二个文件大小要远远大于另外两个文件。

这时候我们再去看一下,顺序是什么样子的。

结果如何呢?

你会发现我们的加载顺序和上面一模一样。

这是为什么呢?第二个文件明明要大于另外两个文件呀。

这里就要说到 script标签 的柱塞式执行方式了。

3. script 标签的属性


在说上面的问题之前,咱们先回顾一下,script 标签 的六个属性。

属性名介绍
1type
2src
3charset
4language
5async
6defer

注意:
虽然text/javascript 和text/ecmascript 都已经不被推荐使用,
但人们一直以来使用的都还是text/javascript。
实际上,服务端在传送JavaScript 文件时使用的 MIME 类型通常是application/x-javascript,
但在type中设置这个值却可能导致脚本被忽略。
另外,在非IE浏览器中
还可以使用以下值:application/javascript 和application/ecmascript。
考虑到约定成俗和最大限度的浏览器兼容性,
目前type 属性的值依旧还是text/javascript。

除此之外,属性 1 ~ 4 是 HTML4.01中定义的,而 5 和 6 则是 HTML 5 中新增的内容,那我们接下来就专门针对这两个新属性,来看一下,script 的柱塞式执行。

4.async属性


async属性是HTML5的新特性,这意味着其兼容性并不乐观(IE10+)。

async表示该script标签并不柱塞,也不同步执行。

浏览器只需要在脚本下载完毕后再执行即可——不必柱塞页面渲染等待该脚本的下载和执行。

如下代码[^4],会得到三个alert,但是alert的内容分别是”A”,”C”,”B”。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>李鹏:3206064928</title>
</head>
<body></body>
<script  src="https://snipt.net/raw/7b08744009c450e07c0bfc1d606fc72e/"></script>
<script  src="https://snipt.net/raw/a2e8c05c1f6fc0e47d259aa899304e89/" async="async"></script>
<script  src="https://snipt.net/raw/4fab3017d3d46cbfc4bbd88aab006650/"></script>
</html>

运行结果如下:

可以看到,第二个script标签在加入async后,并没有阻止后续文档解析和脚本执行。

考究这个属性产生的原有,其实有大量的脚本加载器在做这样的事情:

var script = document.createElement("script");
script.src = "file.js";
document.body.appendChild(script);

那么我们不难想象,通过脚本异步插入的script标签达到的效果和带async属性的script标签是一样的。

换句话说,由脚本插入的script标签默认是async的。

另外,对內联脚本设置async属性是没有意义的,也不产生其他效果。

其包含的脚本总是立即执行的。

5. defer属性


带有defer属性的脚本,同样会推迟脚本的执行,并且不会阻止文档解析。

就如同这个脚本,放置到了文档的末尾(</body>之前)。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>李鹏:3206064928</title>
</head>
<body></body>
<script  src="https://snipt.net/raw/7b08744009c450e07c0bfc1d606fc72e/"></script>
<script  src="https://snipt.net/raw/a2e8c05c1f6fc0e47d259aa899304e89/" defer="defer"></script>
<script  src="https://snipt.net/raw/4fab3017d3d46cbfc4bbd88aab006650/"></script>
</html>

上面的代码的宏观现象和加了async属性的例子是一样的,都是会得到”A”、”C”、”B”的三个alert。

但是其原理是不一样的。

defer属性是会确保脚本在文档解析完毕后执行的。

即使这个脚本在文档解析过程中就已经下载完毕变成可执行的状态,

浏览器也会推迟这个脚本的执行,直到文档解析完毕,并在DOMContentLoaded之前。

同时,带有defer的脚本彼此之间,能保证其执行顺序。

注意,defer属性并不是每个浏览器支持,

即便支持的浏览器,也会因为版本不一样导致具体行为不一致。

另外,大家可以通过将script标签放置到文档末尾这种简单的做法达到defer属性一样的效果。

defer属性早在IE4就被支持,但是这个defer属性和现代浏览器的行为是有区别的。

只有IE10以上,才开始按照标准执行defer属性。

6. async与defer的影响


参考W3C的官方文档,defer和async两个属性是可以互相影响的:

There are three possible modes that can be selected using these attributes. If the async attribute is present, then the script will be executed asynchronously, as soon as it is available. If the async attribute is not present but the defer attribute is present, then the script is executed when the page has finished parsing. If neither attribute is present, then the script is fetched and executed immediately, before the user agent continues parsing the page.

简单的归纳:

  • 仅有async属性,脚本会异步执行
  • 仅有defer属性,脚本会在文档解析完毕后执行
  • 两个属性都没有,脚本会被同步下载并执行,期间会柱塞文档解析

规范里没有提到两种属性都有时的效果,但这是文档中被允许的。

这样的具体效果会在后面讨论。

7. document.write的影响

docuemnt.write允许向打开的文档流中写入文档内容;

内嵌到HTML里面的docuemnt.write可以就地添加文档内容。

考虑到docuemnt.write写入script标签的情况:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>李鹏:3206064928</title>
</head>
<body></body>
<script  src="https://snipt.net/raw/7b08744009c450e07c0bfc1d606fc72e/"></script>
<script>document.write("\<script  src=https://snipt.net/raw/a2e8c05c1f6fc0e47d259aa899304e89 \/\>\<\/script\>");</script>
<script  src="https://snipt.net/raw/4fab3017d3d46cbfc4bbd88aab006650/"></script>
</html>

执行结果如下:

我们观察到执行顺序和普通的script标签没有区别。

即使你插入的标签带有async或defer,其行为也是没有区别的。

让人纠结的是反过来使用。

将我们的 document.write 写在页面中时,其余加载按照正常顺序。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>李鹏:3206064928</title>
</head>
<body></body>
<script src="https://snipt.net/raw/7b08744009c450e07c0bfc1d606fc72e/"></script>
<script src="https://snipt.net/raw/773d794c9051a238e5c102e65dbaa2e9/"></script>
<script src="https://snipt.net/raw/4fab3017d3d46cbfc4bbd88aab006650/"></script>
</html>

加载结果如下:

由于第二个脚本是通过document.write写入的。

被延迟的脚本在执行时,document已经关闭,document.write是没有任何效果的。

所以,不管使用defer还是async,第二个脚本始终没有运行。


本文参考于 《JS 编程指南》

script标签的defer和async属性的使用 defer属性用于延迟脚本的执行,脚本会按照它们在页面中出现的顺序依次执行,而不阻塞页面的解析和渲染过程。async属性用于异步加载和执行脚本,脚本会在加载完成后立即执行,不需要等待页面解析完毕,但脚本的执行顺序是不确定的。当浏览器遇到带有defer属性的script标签时,它会继续解析页面的其余部分,并在页面解析完毕后再按照顺序执行defer脚本。需要注意的是,由于async脚本的执行不会等待页面解析完毕,所以它们的执行顺序是不确定的。因此,async属性适合用于独立的脚本,而不适合有依赖关系的脚本。 阅读详情

相关推荐

OpenV2X 车路协同开源平台 Columbia 版本正式发布!

OpenV2X车路协同开源平台Columbia 版本正式发布!

weixin_65571684的博客 1198

浏览器环境中javascript加载执行顺序及注意点

1、html中通过script标签引入的javascript代码。 这种js代码是自上而下执行的,不论其加载快慢,始终都是按照顺序执行。 2、不要在加载脚本中使用document.write插入任何javascript代码。 因为这种方式写入的JS代码在执行流程中会出现一些问题,所以最好就是不要使用这种方式在加载过程中插入JS代码。 外部脚本:通过script src引入。 内部脚本:直接script内嵌。 注:document.write写入内容的位置还存在一个问题,加入在<head&.

lengye7的博客 3858

神联动:LSTM+卡尔曼滤波!一区大门轻松开!

近来热度飙升,成为时间序列预测和状态估计等领域的香饽饽,非常好发高区!主要在于:这两者结合,不仅能提高模型预测准确性;还能拓展应用场景,为我们的论文创新提供发挥空间,且当下还在蓝海阶段,还不算卷。具体点说:卡尔曼滤波擅长处理线性状态估计和噪声,能使LSTM更好地适应动态环境的变化,减少噪声干扰,降低预测误差。而LSTM通过捕捉长期依赖关系,擅长处理非线性时间序列,能够弥补卡尔曼滤波在这方面的不足,从而把应用场景从传统的状态估计,延伸到金融预测、工业检测、自动驾驶等任务。

2401_82426425的博客 2208

如何保证script标签的加载顺序

本章博文主要解决script标签的加载顺序问题。

李卓书 2729

(目录)微气候模型ENVI-met模拟的基本使用教程

ENVI-met模拟操作系列(一) 介绍:

ysqzhatian的博客 2万+

零基础玩转华为AP 4050DN-HD:FAT模式家庭无线网络配置实战

本文为零基础用户提供华为AP 4050DN-HD从FIT模式转换为FAT模式的完整实战教程。详细介绍了固件升级、模式转换以及配置家庭无线网络(包括路由、DHCP、Wi-Fi和NAT)的每一步操作,帮助用户将企业级瘦AP改造为高性能家庭胖AP,打造稳定可靠的家庭网络环境。

weixin_29196613的博客 630

JS中script脚本的执行顺序

JS中script脚本的执行顺序 在HTML中引入script脚本时,最普通的用法是直接引用,此时浏览器按顺序解析HTML,当解析到script的位置时,加载脚本并在加载完毕时立即执行脚本,在加载和执行的过程中会暂停HTML的解析。此种方法的问题是一旦因为某些原因导致脚本的加载时间过长,会影响页面的渲染,降低用户体验。所以在script标签中存在两个参数async和defer,可以控制脚本的加载和执行时间。 async async表示异步,script标签中有async参数时,浏览器会在解析到此处时异步加载

qq_38446108的博客 1524

import-im6.q16: attempt to perform an operation not allowed by the security policy `PS‘ @ error/cons

这六个 policy 是使用 XML 格式描述的安全策略。要将其中的限制注释掉,在每个 policy 开始和结束的标记之间添加注释标记“

m0_60657960的博客 1908

JavaScript执行顺序总结

js的执行顺序

qq_41872385的博客 5540

Xilinx高级调试方法--远程调试

本文主要介绍Xilinx的一些高级调试方法,以及如何使用Xilinx的相关IP。

斌赋的博客 3308

使用 Visual Studio Code 连接 ABAP On-Premise 系统做开发的详细配置步骤

本文详细介绍了如何在Visual Studio Code中通过ABAP Development Tools扩展连接ABAP On-Premise系统。关键步骤包括:通过Ctrl+Shift+P打开命令行面板选择「ABAP: New Destination...」创建RFC连接(仅支持SSO单点登录),选择本地SAPGUI中已有的系统,输入Client ID、语言和用户名(无需密码),最后将目标系统添加到工作区即可开始开发。文章强调了企业安全考虑下仅支持SSO的设计理念,并展示了连接配置的JSON格式示例。整

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 986

html解析和渲染过程 与 Script标签和脚本执行顺序

几个首要特性: script标签(不带defer或async属性)的会阻止文档渲染。相关脚本会立即下载并执行。 document.currentScript可以获得当前正在运行的脚本(Chrome 29+, FF4+) 脚本顺序再默认情况下和script标签出现的顺序一致 有defer或async属性(defer和async没有完全兼容所有浏览器) 仅有async...

weixin_34137799的博客 481

手把手教你学Simulink——基于Simulink的多用户MIMO系统仿真建模示例

多用户MIMO概述在多用户MIMO系统中,基站配备多个天线,可以同时与多个用户进行通信。利用空间复用技术,不同用户的信号被分配到不同的空间流上,从而实现频谱资源的高效利用。多用户MIMO的核心挑战包括信道估计、波束成形设计以及干扰管理。关键技术点波束成形:通过调整发射信号的相位和幅度,在特定方向上增强信号强度并减少干扰。信道估计:获取每个用户的信道状态信息(CSI),用于优化波束成形矩阵。调制与解调:选择合适的调制方式(如QPSK、16-QAM等)以适应不同用户的信道条件。干扰消除。

MHD0815的博客 269

script标签中的defer和async

普通script: 文档解析的过程中,如果遇到script脚本,停止页面的解析渲染, 下载script脚本。 如果是多个script脚本, 近似于同时并行下载script脚本。 不论script脚本哪个先下载好, 都按照html中的先后顺序依此执行。 即如果后面的script脚本先下载好, 要等前面的script脚本下载好并执行后, 才能执行。 执行script脚本时, 也是停止页面的解析渲染。 执行完script脚本, 继续页面的解析渲染。 执行完script脚本和页面解析渲染完, 才会...

chenrongwei92的博客 9715

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

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

如果script标签中没有defer或async属性,浏览器在渲染中遇到script标签就会停止渲染,下载执行js代码,等待JS执行完毕后,浏览器再从中断的地方恢复渲染。这就会造成浏览器阻塞,如果你想首屏渲染的越快,就越不应该在首屏就加载 JS 文件,这也是都建议将 script 标签放在 body 标签底部的原因。当然在当下,并不是说 script 标签必须放在底部,因为你可以给 script...

diwang_718的博客 1095

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

图解 script 标签中的 async 和 defer 属性

async defer scirpt 阻塞渲染

guxin_duyin的博客 681

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

script标签中的async和defer

当浏览器遇到带有 async 属性的 script 时,请求该脚本的网络请求是异步的,不会阻塞浏览器解析 HTML,一旦网络请求回来之后,如果此时 HTML 还没有解析完,浏览器会暂停解析,先让 JS 引擎执行代码,执行完毕后再进行解析。当浏览器遇到带有 defer 属性的 script 时,获取该脚本的网络请求也是异步的,不会阻塞浏览器解析 HTML,一旦网络请求回来之后,如果此时 HTML 还没有解析完,浏览器不会暂停解析并执行 JS 代码,而是等待 HTML 解析完毕再执行 JS 代码。

x0926的博客 874

按照顺序执行_动态插入的script脚本执行时间

在一些场景我们会动态插入script标签加载js。譬如某个js文件不是很重要,并不是整个页面需要的脚本,可能只是某个功能需要的,这个功能可能是用户点击了某个按钮才触发,入口比较深。且和你页面本身的结构不同类,譬如你是基于react的页面,这个功能的js是jquery插件。这种js文件我一般采用动态加载方式引入。如果你用js动态插入script,那么它什么时候执行呢,如果插入多个scrip...

weixin_39978749的博客 441

script标签

script 元素既可以包含脚本语句,也可以通过 src 属性指向外部脚本文件。默认情况下script标签的会阻止文档渲染,相关脚本会立即下载并执行。 属性 在HTML5中script主要有以下几个属性:async,defer,charset,src,type async(可选):     关键词:外部文件,异步下载,异步执行;     当标签中包含这个属性时会立即下载脚本(外部...

weixin_30617797的博客 163

script 标签中的 async 和 defer 的区别

在前端开发中,<script>标签的async和defer属性均用于优化脚本加载与页面渲染的关系,避免脚本阻塞页面解析,但二者在上存在关键区别。

jj1245_的博客 1097

script 标签中 defer 和 async 的区别

2.3.

我的博客 227

script标签中的属性

script标签中defer和async属性的区别script标签中defer和async属性的区别 script标签中defer和async属性的区别 script标签存在两个属性,defer和async,因此script标签的使用分为三种情况: 1. 没有defer或async属性,浏览器会立即加载并执行相应的脚本。也就是说在渲染script标签之后的文档之前,不等待后续加载的文档元素,读到就开始加载和执行,此举会阻塞后续文档的加载;    ①【如果放在head头里面引入,异步加载资源,但会阻塞的渲染,

dou_xiaobao的博客 997

script标签的知识

script标签的知识 script标签的执行顺序 script 是按照它们出现的顺序被执行的,执行时会阻塞程序运行,建议页面实现类的js放到body之前,动作、交互、事件驱动、对于dom属性的访问操作可以放在body的dom之后尾标签之前。这样会加快网页的加载速度。 script标签的async和defer属性 HTML5 添加了两个工具来控制脚本的执行。 async 表示“不用马上执行它”。更具体地它表示:我不介意你在整个网页加载完成之后执行这个脚本,把它放在其他脚本执行之后。这对于统计

在下魔王ii的博客 1388

【JS】script标签defer和async

【JS】script标签defer和async

owo_ovo的博客 553
上一篇: Mac 终端命令大全
下一篇: 细数前端中的一些黑科技
MR_LP
博客等级 码龄11年 236粉丝 89原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值