第2章 HTML中的JavaScript
2.1 <script>
元素
将JavaScript插入HTML的主要方法是使用<script>
元素。这个元素是由网景公司创造出来的。后来这个元素被正式加入到HTML规范。<script>
元素有下列八个属性:
·async:可选。表示应该立即下载脚本,但不能阻止其他页面动作,比如下载资源或等待其他脚本加载,只对外部脚本文件有效。
·charest:可选。使用src属性指定的代码字符集。这个属性很少使用,因为大多数浏览器不在乎它的值
·crossorigin:可选。配置相关请求的CORS(跨域资源共享)设置。默认不使用CORS。crossorigin="anonymous"配置文件请求不必设置凭据标志。crossorigin="use-credentials"设置凭据标志,意味着出战请求会包含凭据。
·defer:可选。表示脚本可以延迟到文档完全被解析和显示之后再执行。只对外部脚本文件有效。
·integrity:可选。允许比对接收到的资源和指定的加密签名以验证子资源完整性(SRI)。如果接收到的资源的签名与这个属性指定的签名不匹配,则页面会报错,脚本不会执行。这个属性可以用于确保内容分发网络(CDN)不会提供恶意内容
·src:可选。表示包含要执行的代码的外部文件
·type: 可选。代替language,表示代码块中脚本语言的内容类型。按照惯例,这个值始终都是"text/javascript"
使用<script>
的方式有两种:通过它直接在网页中嵌入JavaScript代码,以及通过它在网页中包含外部JavaScript文件。
要嵌入行内JavaScript代码,直接把代码放在<script>
元素中就行:
<script>
function sayHi(){
console.log("Hi")
}
</script>
包含在 <script>
内的代码会被从上到下解释。在上面的例子中,被解释的是一个函数定义,并且该函数会被保存在解释器环境中。在<script>
元素中的代码被计算完成之前,页面的其余内容不会被加载,也不会被显示。
在使用行内JavaScript代码时,要注意代码中不能出现字符串</script>
比如,下面的代码会导致浏览器报错:
<script>
function sayJS(){
console.log("</script>")
}
</script>
浏览器解析行内脚本的方式决定了它在看到字符串</script>
。想要避免这种情况,只需要转译字符\
要包含外部文件中的JavaScript,就必须要使用src属性。这个属性的值是一个URL,指向JS文件
<script src="example.js"></script>
另外,使用了src属性的<script>
元素不应该再在<script>
和</script>
标签中再包含其他JavaScript代码。如果两者都提供的话,则浏览器只会下载并执行脚本文件,从而忽略行内代码。
src属性可以是一个完整的URL,而且这个URL指向的资源可以跟包含它的HTML页面不在同一个域,这也是跨域问题的一个解决办法。
浏览器在解析这个资源时,会向src属性指定的路径发送一个get请求,以取得相应资源,假定是一个JS文件。这个初始请求不受浏览器同源策略限制,但返回并被执行的JavaScript则受限制。
2.1.1 标签位置
过去,所有<script>
元素都被放在页面的<head>
标签内,这种做法主要目的是把外部的CSS和JavaScript 文件都集中放到一起。不过,把所有的JavaScript文件都放到<head>
里,也就意味着必须把所有的JavaScript代码都下载、解析和解释完成后,才开始渲染页面(页面在浏览器解析到<body>
的其实标签时开始渲染)对于很多JavaScript的页面,这会导致页面渲染的明显延迟,在此期间浏览器窗口完全空白。为解决这个问题,现在Web应用程序通常将所有JavaScript引用放在<body>
元素中的页面内容后面
2.1.2 推迟执行脚本
HTML4.01为<acript>
元素定义了一个叫defer的属性。这个属性表示脚本在执行的时候不会改变页面的结构。也就是说,脚本会在整个页面被解析完以后再执行。
<head>
<script defer src="example.js"></script>
</head>
一般下的使用,想要脚本延迟运行,可以把脚本放在body的最下面,defer属性只对外部的文件起作用。
2.1.3 异步执行脚本
不推荐使用
2.1.4 动态加载脚本
除了<script>
标签,JavaScript可以使用DOM API,所以通过向DOM中动态添加script元素同样可以添加脚本。
let script = document.createElememt('script')
script.src = 'test.js'
document.head.appendChild(script)
上面这种方式默认是异步方式加载的,相当于添加了async属性。因此,如果要统一动态脚本的加载行为,可以明确将其设置为同步加载:
let script = document.createElememt('script')
script.src = 'test.js'
script.saync = false
document.head.appendChild(script)
以这种方式获取的资源对浏览器预加载器是不可见的。这会严重影响它们在资源获取队列中的优先级。根据应用程序的工作方式以及怎么使用,这种方式可能会严重影响性能。我们可以在文档头部显式声明它们
<link rel="preload" href="test.js">
2.1.5 XHTML的变化
XHTML(可扩展超文本标记语言)是将HTML作为XML的应用重新包装的结果。
XHTML中使用JavaScript必须指定type属性且值为text/javascript
避免XHTML中语法错误的方式有两种:
- 第一种是把所有的小于号改为
<
这种方式的缺点是影响阅读 - 把所有的代码都包含到一个CDATA块中。在XHTML(以及XML)中CDATA块表示文档中可以包含任意文本的区块,其内容不作为标签来解析。格式如下:
<script type="text/javascript">
//<![CDATA[
function logA(){
console.log('A')
}
//]]>
</script>
2.2 行内文件与外部文件
推荐使用外部文件的原因:
- 可维护性。
- 缓存。如果两个页面用到了同一个js文件,可以加载更快
- 适应未来。 把JS放到文件外面,就不需要考虑XHML的适配问题
2.3 文档模式
三种模式:混杂模式、标准模式和准标准模式。
2.4 <noscript>
元素
针对早期浏览器不支持JavaScript的问题,需要一个页面优雅降级的处理方案。下面两种情况,浏览器将显示包含在<noscript>
中的内容:
-
浏览器不支持脚本
-
浏览器对脚本的支持被关闭
任何一个条件被蛮子,包含在其中的内容就会被渲染
2.5 小结
- 要包含外部JavaScript文件,必须将src属性设置为要包含文件的URL。文本可以跟网页在同一台服务器上,也可以位于完全不同的域
- 所有
<script>
元素会依照它们在网页中出现的次序被解释。在不使用defer和async属性的情况下,包含在<script>
元素中的代码必须严格按次序解释。 - 通常把
<script>
元素放到页面末尾,介于主内容之后及</body>
标签之前 - 可以使用defer属性把脚本推迟到文档渲染完毕后再执行。推迟的脚本原则上按照它们被列出的次序执行
- 可以使用async属性表示脚本不需要等待其他脚本,同时也不阻塞文档渲染
- 通过使用
<noscript>
元素,可以指定在浏览器不支持脚本时显示的内容