[转]Script标签和脚本执行顺序
Script标签和脚本执行顺序
这里详细聊聊和script标签相关的脚本执行顺序。
Script标签的默认行为
几个首要特性:
- script标签(不带
defer或async属性)的会阻止文档渲染。相关脚本会立即下载并执行。 document.currentScript可以获得当前正在运行的脚本(Chrome 29+, FF4+)- 脚本顺序再默认情况下和script标签出现的顺序一致
假设如下简单代码1,最终会产生三个alert依次为“A”、“B”、“C”。
<!-- HTML Code -->
<script>alert("A");</script>
<script>alert("B");</script>
<script>alert("C");</script>
我们再考虑有网络请求的情况2:
<!-- HTML code -->
<script src="https://snipt.net/raw/7b08744009c450e07c0bfc1d606fc72e/"></script>
<script src="https://snipt.net/raw/a2e8c05c1f6fc0e47d259aa899304e89/"></script>
<script src="https://snipt.net/raw/4fab3017d3d46cbfc4bbd88aab006650/"></script>
三个文件都需要先下载再运行,且第二个文件的尺寸远大于另外两个文件。但结果依然是弹出三个alert,内容分别是”A”、”B”、”C”。
从上面两个例子,可以充分了解到script标签的柱塞式执行。
async属性
async属性是HTML5的新特性3,这意味着其兼容性并不乐观(IE10+)。
async表示该script标签并不柱塞,也不同步执行。浏览器只需要在脚本下载完毕后再执行即可——不必柱塞页面渲染等待该脚本的下载和执行。
如下代码4,会得到三个alert,但是alert的内容分别是”A”,”C”,”B”。
<!-- HTML code -->
<script src="https://snipt.net/raw/7b08744009c450e07c0bfc1d606fc72e/"></script>
<script src="https://snipt.net/raw/a2e8c05c1f6fc0e47d259aa899304e89/" async=true></script>
<script src="https://snipt.net/raw/4fab3017d3d46cbfc4bbd88aab006650/"></script>
可以看到,第二个script标签在加入async并没有阻止后续文档解析和脚本执行。
考究这个属性产生的原有,其实有大量的脚本加载器在做这样的事情:
var script = document.createElement("script");
script.src = "file.js";
document.body.appendChild(script);
不难想象,通过脚本异步插入的script标签达到的效果和带async属性的script标签是一样的。换句话说,由脚本插入的script标签默认是async的。
另外,对內联脚本设置async属性是没有意义的,也不产生其他效果。其包含的脚本总是立即执行的。
defer属性
带有defer属性的脚本,同样会推迟脚本的执行,并且不会阻止文档解析。就如同这个脚本,放置到了文档的末尾(</body>之前)。
如下代码5的宏观现象和加了async属性的例子是一样的,都会得到”A”、”C”、”B”的三个alert。但是其原理是不一样的。
<!-- HTML code -->
<script src="https://snipt.net/raw/7b08744009c450e07c0bfc1d606fc72e/"></script>
<script src="https://snipt.net/raw/a2e8c05c1f6fc0e47d259aa899304e89/" defer=true></script>
<script src="https://snipt.net/raw/4fab3017d3d46cbfc4bbd88aab006650/"></script>
defer属性是会确保脚本在文档解析完毕后执行的——即使这个脚本在文档解析过程中就已经下载完毕变成可执行的状态,浏览器也会推迟这个脚本的执行,直到文档解析完毕6,并在DOMContentLoaded之前7。
同时,带有defer的脚本彼此之间,能保证其执行顺序。
注意,defer属性并不是每个浏览器支持,即便支持的浏览器,也会因为版本不一样导致具体行为不一致。另外,大家可以通过将script标签放置到文档末尾这种简单的做法达到defer属性一样的效果。
defer属性早在IE4就被支持,但是这个defer属性和现代浏览器的行为是有区别的。只有IE10以上,才开始按照标准执行defer属性。
async与defer的影响
参考W3C的官方文档8,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属性,脚本会在文档解析完毕后执行
- 两个属性都没有,脚本会被同步下载并执行,期间会柱塞文档解析
规范里没有提到两种属性都有时的效果,但这是文档中被允许的。这样的具体效果会在后面讨论。
document.write的影响
docuemnt.write允许向打开的文档流中写入文档内容;内嵌到HTML里面的docuemnt.write可以就地添加文档内容。考虑到docuemnt.write写入script标签的情况9:
<!-- HTML code -->
<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>
观察到执行顺序和普通的script标签没有区别。即使你插入的标签带有async或defer,其行为也是没有区别的。
让人纠结的是反过来10使用。由于第二个脚本是通过document.write写入的。被延迟的脚本在执行时,document已经关闭,document.write是没有任何效果的。所以,不管使用defer还是async,第二个脚本始终没有运行。
原文:
http://pij.robinqu.me/Browser_Scripting/Document_Loading/ScriptTag.html
[转]Script标签和脚本执行顺序的更多相关文章
- MonoBehaviour Lifecycle(生命周期/脚本执行顺序)
脚本执行顺序 前言 搭建一个示例来验证Unity脚本的执行顺序,大概测试以下部分: 物理方面(Physics) 渲染(Scene rendering) 输入事件(InputEvent) 流程图 Uni ...
- script标签引入脚本的引入位置与效果
用script标签引入脚本的引入位置大致有两种情况: 1,在head中引入: 2,在body末尾引入: 浏览器由上到下解析代码,正常情况下,先解析head中的代码,在解析body中的代码:放在head ...
- 浅谈Unity的脚本执行顺序
一.添加脚本的顺序 这是一张官方的脚本顺序图 一般,当我们把脚本绑定在游戏对象上时,或者点击绑定好的脚本的reset按钮时,会调用Reset() 当我们初始化一个对象时,会先调用Awake()在调用O ...
- unity脚本执行顺序
Awake ->OnEable-> Start ->-> FixedUpdate-> Update -> LateUpdate ->OnGUI ->R ...
- Unity脚本执行顺序自研框架
本文章由cartzhang编写,转载请注明出处. 所有权利保留. 文章链接:http://blog.csdn.net/cartzhang/article/details/52372611 作者:car ...
- html/css基础篇——link和@inport详解以及脚本执行顺序探讨
先说一说两者之间的异同 两者都可以引用外部CSS的方式,现在主流浏览器两者都支持(ps:@import是CSS2.1提出的),但是存在一定的区别: 1.link是XHTML标签,除了加载CSS外,还可 ...
- Unity 继承MonoBehaviour脚本 执行顺序 详解
先看结果 Awake ->OnEnable-> Start ->-> FixedUpdate-> Update -> LateUpdate ->OnGUI ...
- unity 脚本执行顺序设置 Script Execution Order Settings
通过Edit->Project Settings->Script Execution Order打开MonoManager面板 或者选择任意脚本在Inspector视图中点击Execu ...
- js——<script>标签的加载顺序
用了很久的JavaScript,今天突然就碰见了将一个js文件放在<head></head>与<body></body>标签中,一个不可以执行,一个可以 ...
随机推荐
- <关于并发框架>Java原生线程池原理及Guava与之的补充
原创博客,转载请联系博主! 转眼快两个月没有更新自己的博客了. 一来感觉自己要学的东西还是太多,与其花几个小时写下经验分享倒不如多看几点技术书. 二来放眼网上已经有很多成熟的中文文章介绍这些用法,自己 ...
- 用JAR的方式运行SpringBoot项目
接 Spring Boot 快速入门(Eclipse) 步骤一:部署方式 Springboot 和 web 应用程序不一样,其本质上是一个 Java 应用程序,那么又如何部署呢? 通常来说,Sprin ...
- LeetCode——Number Complement
LeetCode--Number Complement Question Given a positive integer, output its complement number. The com ...
- DPDK编程指南 2.概述
本章节给出了DPDK架构的一个全局概述. DPDK的主要目的就是为数据面快速报文处理应用程序提供一个简洁完整的框架.用户可以通过代码来理解其中使用的一些技术,构建自己的应用程序或添加自己的协议栈.Al ...
- git生成和检查秘钥操作
查看本地是否有git config的配置: git config --list 设置用户名和邮箱: $git config --global user.email "tanteng@gmai ...
- Appium 自动化测试(5)-- Appium详细介绍:Appium 手机自动化测试_TesterHome公开版pdf
- C语言小知识点汇集
1. 三元表达式“?:”冒号两边的两个操作数类型必须一致. 2. 枚举变量的sizeof值同int型一样为4. 3. 为了消除不必要的计算 &&两侧的表达式,当左侧即第1个表达式不成立 ...
- Cassandra二级索引原理——新创建了一张表格,同时将原始表格之中的索引字段作为新索引表的Primary Key,并且存储的值为原始数据的Primary Key,然后再通过pk一级索引找到真正的值
1.什么是二级索引? 我们前面已经介绍过Cassandra之中有各种Key,比如Primary Key, Cluster Key 等等.如果您对这部分概念并不熟悉,可以参考之前的文章: [Cassan ...
- 使用ettercap构建arp欺骗构建
0.准备: 安装:ettercap apt-get install cmake libncurses5-dev libssl-dev libpcap-dev libnet1-dev git clone ...
- monkey 原理,环境搭建、命令详解
一.monkey测试的相关的原理 monkey测试的原理就是利用socket通讯的方式来模拟用户的按键输入,触摸屏输入,手势输入等,看设备多长时间会出异常.当Monkey程序在模拟器或设备运行的时候, ...