<script>标签元素
可选属性:
async: 不用等待脚本下载执行完后再加载页面,也不需要等待异步脚本加载完成后再加载其他脚本。
有async标签的脚本不能保证按照出现的次序执行。
charset: src指定的代码的字符集
crossorigin: 配置相关请求的跨资源共享设置(CORS)。默认不使用。crossorigin="anonymous"配置文件请求不必设置凭据标志。crossorigin="use-credentials"设置凭据标志,出站请求会包含凭据
defer: 表示脚本可以等到文档解析或显示完成后再执行。 浏览器会忽略行内脚本的defer属性
intergrity: 允许比对接受到的资源和指定的加密签名以验证资源的完整性。签名不匹配会报错。
type: 代替language属性,始终是"text/javascript"
如果值是"module",代码会被当成ES6模块且只有这种情况代码中才能出现import/export关键字
src: 外部文件地址。使用src属性的<script>元素,会忽略标签内的行内代码。
浏览器不会检查外部文件的扩展名,但是要保证返回正确的MINE类型。
行内脚本如果包含</script>字符串时,需要添加转义字符。如:
<script>
function test () {
console.log("</script>");
console.log("<\/script>");
}
</script>
<script>标签位置
<script>元素至于页面的<head>标签内,目的主要是把外部的css和js文件集中到一起。但是这样有一个不好的地方。 必须把所有的JavaScript代码下载、解析和解释完成以后,才能开始渲染页面。对于大量外部js引入的页面,加载的时间内浏览器窗口将完全空白。
优化方式一般是,把<script>元素移植<body>标签内的结尾处。
当然也可以给<head>标签中的 !!外部!! <script>元素添加defer属性。
或者添加async属性来异步加载。
<script>元素的加载顺序
1.HTML5规范要求脚本按照出现的顺序执行。
2.如果外部脚本申明了defer属性,它们会在浏览器执行到</html>标签结束后才会执行,且如果有多个defer属性,按照规范也会按照出现顺序相应地延迟执行。
这里就会有一个问题。如果我在</html>标签之后手动添加了行内<script>或者外部<script>(叫脚本B吧),并且我在<head>标签内引入了外部<sctipt>(叫脚本A吧),并且脚本A定义了defer属性。那么实际渲染过程中A, B的执行顺序是什么样的。这里书中目前并没有看到,自己做一个简单的测试。
如图,我们先测试正常情况下的logs顺序,引入的testorder.js内容为console.log('A');
它的输出结果如同预期。
然后我们给外部引入的script添加defer属性,看看它是什么样的输出结果:
按照理解的话应该是B C A D,那么结果如何呢:
这样写可能不太清晰,那我们多加几个引用:(外部脚本分别log A1 A2 A3 A4)
输出结果呢:
那么我们的第二点标题可能需要改写了,其实是
如果外部脚本申明了defer属性,它们会在浏览器执行到</html>标签结束后且在页面内的其他无defer属性的<script>执行后才会执行,且如果有多个defer属性,按照规范也会按照出现顺序相应地延迟执行。
其实还有一个小问题,如果带上了setTimeout以后的顺序是不是还是如此。
A1延迟200, A2延迟100, A3延迟50,A4延迟1,C延迟10,D2延迟100
实际的输出就需要理解一下了:
3.HTML5 规范要求脚本按照它们出现的先后顺序执行,因此第一个延迟脚本会先于第二个延迟脚本执行,而这两个脚本会先于 DOMContentLoaded 事件执行。在现实当中,延迟脚本并不一定会按照顺序执行,也不一定会在 DOMContentLoaded 事件触发前执行,因此最好只包含一个延迟脚本。(defer)
个人测试没有出现过延后的情况。个人感觉书上这么写的原因可能是因为, HTML5规范如此,但是每个浏览器厂商未必会按照这个规范实现(有待考究)
4.async 只适用于外部脚本文件,并告诉浏览器立即下载文件,下载完成后立即执行。但与 defer不同的是,标记为 async 的脚本并不保证按照指定它们的先后顺序执行。async脚本可以保证在load事件前执行,但是有可能在DOMContentLoaded事件之前或之后。
有关DOMContentLoaded 与 load区别,可以参见演示链接。
5.(补充)async和defer的区别
这里引用一下知乎@ 编译青春的文章,讲的比较详细与直观 : 你不知道的 DOMContentLoaded
动态加载脚本
以这种方式获取的资源对浏览器的预加载器是不可见的,这回严重影响到它们在资源获取队列中的优先级。
想让预加载器知道这些动态请求文件的存在,可以再文档头部显示申明它们:<link rel="preload" href="gibberish.js">
同样,我们来试验一下动态加载的效果:
异步的情况(会出现多种结果,只列举2种):
同步的情况
无论是否设置同步,动态加载都会出现多种不同结果(只列举三种): 但是顺序只有两种 动态加载的order2在 申明defer的1,3之前或者之后。
多种结果具体是为什么,个人,猜测,是因为动态引入的时候,会根据加载的速度,在加载完成后对HTML文档解析过程进行一个中断。
XHTML中的变化
XHTML中,行内脚本小于号(<)会被解释成标签开始,所以需要替换成(<)
或者使用 "<![CDATA[ " " ]]> "来包裹行内脚本。
<noscript>元素
不支持JavaScript时会显示标签内元素。