将 JavaScript 引入网页,首先要解决它与网页的主导语言 HTML的关系问题。网景公司努力达成了许多向网页中引入通用脚本能力的共识。当初他们的很多工作得到了保留,并且最终形成了 HTML 规范。

<script> 标签

将 JavaScript 插入 HTML 的主要方法是使用<script>元素。这个元素是由网景公司创造出来,并最早在 Netscape Navigator 2 中实现的。后来,这个元素被正式加入到 HTML 规范。<script>元素有下列 8 个属性。

  • src:可选。表示包含要执行的代码的外部文件。

  • async可选。表示应该立即开始下载脚本,但不能阻止其他页面动作,比如下载资源或等待其它脚本加载。只对外部脚本文件有效。

  • crossorigin:可选。配置相关请求的CORS(跨源资源共享)设置。默认不使用CORS。crossorigin= “anonymous” 配置文件请求不必设置凭据标志。crossorigin=“use-credentials” 设置凭据标志,意味着出站请求会包含凭据。

  • defer:可选。表示脚本可以延迟到文档完全被解析和显示之后再执行。只对外部脚本文件有效。在 IE7 及更早的版本中,对行内脚本也可以指定这个属性。

  • charset:可选。使用 src 属性指定的代码字符集。这个属性很少使用,因为大多数浏览器不在乎它的值。

  • integrity:可选。允许比对接收到的资源和指定的加密签名以验证子资源完整性(SRI,Subresource Integrity)。如果接收到的资源的签名与这个属性指定的签名不匹配,则页面会报错,脚本不会执行。这个属性可以用于确保内容分发网络(CDN,Content Delivery Network)不会提供恶意内容。

  • language:废弃。最初用于表示代码块中的脚本语言(如"JavaScript"、“JavaScript 1.2"或"VBScript”)。大多数浏览器都会忽略这个属性,不应该再使用它。

  • type:可选。代替 language,表示代码块中脚本语言的内容类型(也称 MIME 类型)。按照惯例,这个值始终都是"text/javascript",尽管"text/javascript"和"text/ecmascript"都已经废弃了。JavaScript 文件的 MIME 类型通常是"application/x-javascript",不过给type 属性这个值有可能导致脚本被忽略。在非 IE 的浏览器中有效的其他值还有"application/javascript"和"application/ecmascript"。如果这个值是 module,则代码会被当成 ES6 模块,而且只有这时候代码中才能出现 import 和 export 关键字。

使用<script>的方式有两种:

  • 通过它直接在网页中嵌入 JavaScript 代码。嵌入行内 JavaScript 代码,直接把代码放在<script>元素中即可。包含在<script>内的代码会被从上到下解释。被解释的一函数定义会被保存在解释器环境中。在<script>元素中的代码被计算完成之前,页面的其余内容不会被加载,也不会被显示。在使用行内 JavaScript 代码时,要注意代码中不能出现字符串</script>。否则会导致浏览器报错。(想避免这个问题,只需要转义字符<\/script>)

    转义字符指在 JavaScript 中使用反斜杠“\”来向文本字符串添加特殊字符。

  • 通过它在网页中包含外部 JavaScript 文件。包含外部文件中的 JavaScript,就必须使用 src 属性。这个属性的值是一个 URL,指向包含JavaScript 代码的文件。与解释行内 JavaScript 一样,在解释外部 JavaScript 文件时,页面也会阻塞。(阻塞时间也包含下载文件的时间。)在 XHTML 文档中,可以忽略结束标签(单标签形式)以上语法不能在 HTML 文件中使用,因为它是无效的 HTML,有些浏览器不能正常处理,比如 IE。

注意: 按照惯例,外部 JavaScript 文件的扩展名是.js。这不是必需的,因为浏览器不会检查所包含 JavaScript 文件的扩展名。这就为使用服务器端脚本语言动态生成 JavaScript 代码,或者在浏览器中将 JavaScript扩展语言(如TypeScript,或React的 JSX)转译为JavaScript提供了可能性。不过要注意,服务器经常会根据文件扩展来确定响应的正确 MIME 类型。

如果不打算使用 .js 扩展名,一定要确保服务器能返回正确的 MIME 类型。

MIME(Multipurpose Internet Mail Extensions)多用途互联网邮件扩展类型。是设定某种扩展名的文件用一种应用程序来打开的方式类型,当该扩展名文件被访问的时候,浏览器会自动使用指定应用程序来打开。多用于指定一些客户端自定义的文件名,以及一些媒体文件打开方式。

*使用了 src 属性的<script>元素不应该再在<script>和</script>标签中再包含其他 JavaScript 代码。如果两者都提供的话,则浏览器只会下载并执行脚本文件,从而忽略行内代码。

并且浏览器在解析这个资源时,会向 src 属性指定的路径发送一个 GET 请求,以取得相应资源,假定是一个 JavaScript 文件。这个初始的请求不受浏览器同源策略限制,但返回并被执行的 JavaScript 则受限制。当然,这个请求仍然受父页面 HTTP/HTTPS 协议的限制。

来自外部域的代码会被当成加载它的页面的一部分来加载和解释。这个能力可以让我们通过不同的域分发 JavaScript。不过,引用了放在别人服务器上的 JavaScript 文件时要格外小心,因为恶意的程序员随时可能替换这个文件。在包含外部域的 JavaScript 文件时,要确保该域是自己所有的,或者该域是一个可信的来源。<script>标签的 integrity 属性是防范这种问题的一个武器,但这个属性也不是所有浏览器都支持。

标签位置

过去,所有<script>元素都被放在页面的标签内,这种做法的主要目的是把外部的 CSS 和 JavaScript 文件都集中放到一起。不过,把所有 JavaScript文件都放在<head>里,也就意味着必须把所有 JavaScript 代码都下载、解析和解释完成后,才能开始渲染页面(页面在浏览器解析到<body>的起始标签时开始渲染)。对于需要很多 JavaScript 的页面,这会导致页面渲染的明显延迟,在此期间浏览器窗口完全空白。

为解决这个问题,现代 Web 应用程序通常将所有 JavaScript 引用放在<body>元素中的页面内容后面。这样,页面会在处理 JavaScript 代码之前完全渲染页面。用户会感觉页面加载更快了,因为浏览器显示空白页面的时间短了。

推迟执行脚本 defer

HTML 4.01 为<script>元素定义了一个叫 defer 的属性。这个属性表示脚本在执行的时候不会改变页面的结构。也就是说,脚本会被延迟到整个页面都解析完毕后再运行。因此,在<script>元素上设置 defer 属性,相当于告诉浏览器立即下载,但延迟执行。

HTML5 规范要求脚本应该按照它们出现的顺序执行,因此第一个推迟的脚本会在第二个推迟的脚本之前执行,而且两者都会在 DOMContentLoaded 事件之前执行(关于事件,请参考第 17 章)。不过在实际当中,推迟执行的脚本不一定总会按顺序执行或者在 DOMContentLoaded事件之前执行,因此最好只包含一个这样的脚本。

defer 属性只对外部脚本文件才有效。这是 HTML5 中明确规定的,因此支持 HTML5的浏览器会忽略行内脚本的 defer 属性。IE4~7 展示出的都是旧的行为,IE8 及更高版本则支持 HTML5定义的行为。

注意 :对于 XHTML 文档,指定 defer 属性时应该写成 defer=“defer”。

​ defer 属性的支持是从 IE4、Firefox 3.5、Safari 5 和 Chrome 7 开始的。其他所有浏览器则会忽略这个属性,按照通常的做法来处理脚本。考虑到这一点,还是把要推迟执行的脚本放在页面底部比较好。

异步执行脚本async

HTML5 为<script>元素定义了 async 属性。从改变脚本处理方式上看,async 属性与 defer 类似。当然,它们两者也都只适用于外部脚本,都会告诉浏览器立即开始下载。不过,与 defer 不同的是,标记为 async 的脚本并不保证能按照它们出现的次序执行,重点在于它们之间没有依赖关系。给脚本添加 async 属性的目的是告诉浏览器,不必等脚本下载和执行完后再加载页面,同样也不必等到该异步脚本下载和执行后再加载其他脚本。正因为如此,异步脚本不应该在加载期间修改 DOM

异步脚本保证会在页面的 load 事件前执行,但可能会在 DOMContentLoaded 之前或之后。Firefox 3.6、Safari 5 和 Chrome 7 支持异步脚本。使用 async 也会告诉页面你不会使用 document.write,不过好的 Web 开发实践根本就不推荐使用这个方法。

注意: 对于 XHTML 文档,指定 async 属性时应该写成 async=“async”。

动态加载脚本

除了<script>标签,还有其他方式可以加载脚本。因为 JavaScript 可以使用 DOM API,所以通过向 DOM 中动态添加 script 元素同样可以加载指定的脚本。只要创建一个 script 元素并将其添加到DOM 即可。

let script = document.createElement('script'); script.src = 'gibberish.js'; document.head.appendChild(script);

当然,在把 HTMLElement 元素添加到 DOM 且执行到这段代码之前不会发送请求。默认情况下,以这种方式创建的<script>元素是以异步方式加载的,相当于添加了 async 属性。不过这样做可能会有问题,因为所有浏览器都支持 createElement()方法,但不是所有浏览器都支持 async 属性。因此,如果要统一动态脚本的加载行为,可以明确将其设置为同步加载: script.async = false;

以这种方式获取的资源对浏览器预加载器是不可见的。这会严重影响它们在资源获取队列中的优先级。根据应用程序的工作方式以及怎么使用,这种方式可能会严重影响性能。要想让预加载器知道这些动态请求文件的存在,可以在文档头部显式声明它们:<link rel=“preload” href=“gibberish.js”>

XHTML 中的变化

**可扩展超文本标记语言(XHTML,Extensible HyperText Markup Language)是将 HTML 作为 XML的应用重新包装的结果。**与 HTML 不同,在 XHTML 中使用 JavaScript 必须指定 type 属性且值为 text/javascript,HTML 中则可以没有这个属性。XHTML 虽然已经退出历史舞台,但实践中偶尔可能也会遇到遗留代码,为此本节稍作介绍。

在 XHTML 中编写代码的规则比 HTML 中严格,这会影响使用<script>元素嵌入 JavaScript 代码。

<作为一个标签的开始,并且由于作为标签开始的小于号后面不能有空格,这会导致语法错误。

避免 XHTML 中这种语法错误的方法有两种。第一种是把所有小于号(<)都替换成对应的 HTML实体形式(&lt),缺点是会影响阅读。

第二种方法是把所有代码都包含到一个 CDATA 块中。在 XHTML(及 XML)中,CDATA 块表示文档中可以包含任意文本的区块,其内容不作为标签来解析,因此可以在其中包含任意字符,包括小于号,并且不会引发语法错误。使用 CDATA 的格式如下:

在兼容 XHTML 的浏览器中,这样能解决问题。但在不支持 CDATA 块的非 XHTML 兼容浏览器中

则不行。为此,CDATA 标记必须使用 JavaScript 注释来抵消:

//<![CDATA[ //]]>

这种格式适用于所有现代浏览器。虽然有点黑科技的味道,但它可以通过 XHTML 验证,而且对XHTML 之前的浏览器也能优雅地降级。

注意:*XHTML 模式会在页面的 MIME 类型被指定为"application/xhtml+xml"时触发。并不是所有浏览器都支持以这种方式送达的 XHTML。

废弃的语法

自 1995 年 Netscape 2 发布以来,所有浏览器都将 JavaScript 作为默认的编程语言。type 属性使用一个 MIME 类型字符串来标识<script>的内容,但 MIME 类型并没有跨浏览器标准化。即使浏览器默认使用 JavaScript,在某些情况下某个无效或无法识别的 MIME 类型也可能导致浏览器跳过(不执行)相关代码。因此,除非你使用 XHTML 或<script>标签要求或包含非 JavaScript 代码,最佳做法是不指定 type 属性。

在最初采用 script 元素时,它标志着开始走向与传统 HTML 解析不同的流程。对这个元素需要应用特殊的解析规则,而这在不支持 JavaScript 的浏览器(特别是 Mosaic)中会导致问题。不支持的浏览器会把<script>元素的内容输出到页面上,从而破坏页面的外观。

Netscape 联合 Mosaic 拿出了一个解决方案,对不支持 JavaScript 的浏览器隐藏嵌入的 JavaScript 代码。最终方案是把脚本代码包含在一个 HTML 注释中,像这样:

<script><!----></script>

使用这种格式,Mosaic 等浏览器就可以忽略<script>标签中的内容,而支持 JavaScript 的浏览器则必须识别这种模式,将其中的内容作为 JavaScript 来解析。

虽然这种格式仍然可以被所有浏览器识别和解析,但已经不再必要,而且不应该再使用了。在XHTML 模式下,这种格式也会导致脚本被忽略,因为代码处于有效的 XML 注释当中。

推荐使用外部文件的理由

  • 可维护性。JavaScript 代码如果分散到很多 HTML 页面,会导致维护困难。而用一个目录保存所有 JavaScript 文件,则更容易维护,这样开发者就可以独立于使用它们的 HTML 页面来编辑代码。

  • 缓存。浏览器会根据特定的设置缓存所有外部链接的 JavaScript 文件,这意味着如果两个页面都用到同一个文件,则该文件只需下载一次。这最终意味着页面加载更快。

  • 适应未来。通过把 JavaScript 放到外部文件中,就不必考虑用 XHTML 或前面提到的注释黑科技。

包含外部 JavaScript 文件的语法在 HTML 和 XHTML 中是一样的。在配置浏览器请求外部文件时,要重点考虑的一点是它们会占用多少带宽。在 SPDY/HTTP2 中,预请求的消耗已显著降低,以轻量、独立 JavaScript 组件形式向客户端送达脚本更具优势。

在初次请求时,如果浏览器支持 SPDY/HTTP2,就可以从同一个地方取得一批文件,并将它们逐个放到浏览器缓存中。从浏览器角度看,通过 SPDY/HTTP2 获取所有这些独立的资源与获取一个大JavaScript 文件的延迟差不多。

在第二个页面请求时,由于你已经把应用程序切割成了轻量可缓存的文件,第二个页面也依赖的某些组件此时已经存在于浏览器缓存中了。

当然,这里假设浏览器支持 SPDY/HTTP2,只有比较新的浏览器才满足。如果你还想支持那些比较老的浏览器,可能还是用一个大文件更合适。

文档模式

IE5.5 发明了文档模式的概念,即可以使用 doctype 切换文档模式。最初的文档模式有两种:混杂模式(quirks mode)和标准模式(standards mode)。前者让 IE 像 IE5 一样(支持一些非标准的特性),后者让 IE 具有兼容标准的行为。虽然这两种模式的主要区别只体现在通过 CSS 渲染的内容方面,但对JavaScript 也有一些关联影响,或称为副作用。本书会经常提到这些副作用。

IE 初次支持文档模式切换以后,其他浏览器也跟着实现了。随着浏览器的普遍实现,又出现了第三种文档模式:准标准模式(almost standards mode)。这种模式下的浏览器支持很多标准的特性,但是没有标准规定得那么严格。主要区别在于如何对待图片元素周围的空白(在表格中使用图片时最明显)。

准标准模式与标准模式非常接近,很少需要区分。人们在说到“标准模式”时,可能指其中任何一个。而对文档模式的检测(本书后面会讨论)也不会区分它们。本书后面所说的标准模式,指的就是除混杂模式以外的模式。

<noscript>元素

针对早期浏览器不支持 JavaScript 的问题,需要一个页面优雅降级的处理方案。最终,<noscript>元素出现,被用于给不支持 JavaScript 的浏览器提供替代内容。虽然如今的浏览器已经 100%支持JavaScript,但对于禁用 JavaScript 的浏览器来说,这个元素仍然有它的用处。

<noscript>元素可以包含任何可以出现在中的 HTML 元素,<script>除外。在下列两种情况下,浏览器将显示包含在<noscript>中的内容:

  • 浏览器不支持脚本;

  • 浏览器对脚本的支持被关闭。

任何一个条件被满足,包含在<noscript>中的内容就会被渲染。否则,浏览器不会渲染<noscript>中的内容。

<noscript><p>This page requires a JavaScript-enabled browser.</p></noscript>

这个例子是在脚本不可用时让浏览器显示一段话。如果浏览器支持脚本,则用户永远不会看到它。

小结

JavaScript 是通过<script>元素插入到 HTML 页面中的。这个元素可用于把 JavaScript 代码嵌入到

HTML 页面中,跟其他标记混合在一起,也可用于引入保存在外部文件中的 JavaScript。

本章的重点可以总结如下:

  • 要包含外部 JavaScript 文件,必须将 src 属性设置为要包含文件的 URL。文件可以跟网页在同一台服务器上,也可以位于完全不同的域。

  • 所有<script>元素会依照它们在网页中出现的次序被解释。在不使用 defer 和 async 属性的情况下,包含在<script>元素中的代码必须严格按次序解释。

  • 对不推迟执行的脚本,浏览器必须解释完位于<script>元素中的代码,然后才能继续渲染页面的剩余部分。为此,通常应该把<script>元素放到页面末尾,介于主内容之后及</body>标签之前。

  • 可以使用 defer 属性把脚本推迟到文档渲染完毕后再执行。推迟的脚本原则上按照它们被列出的次序执行。

  • 可以使用 async 属性表示脚本不需要等待其他脚本,同时也不阻塞文档渲染,即异步加载。异步脚本不能保证按照它们在页面中出现的次序执行。

  • 通过使用<noscript>元素,可以指定在浏览器不支持脚本时显示的内容。如果浏览器支持并启用脚本,则<noscript>元素中的任何内容都不会被渲染。

再读红宝书(第四版)第二章 html 中的 javascript相关推荐

  1. 2013年CISA中英对照题目解析合集国盟官方(红宝书第四版)

    2013年CISA中英对照题目解析合集国盟官方(红宝书第四版) 本书为国际信息安全学习联盟(简称国盟)CNCISA(中国CISA)家园历年发布的中文对照题目解析合集(红宝书)第四版.本书的目的在于向C ...

  2. 类型“unknown”上不存在属性“foreach”_JavaScript红宝书第四版精简解析系列--映射Map数据类型...

    Map数据类型 顾名思义 也就是映射类型,包含一个[[Entries]]私有特性 我们可以使用一个二维数组作为初始值 const map1 = new Map([[1, 1],[2, 2],[3, 3 ...

  3. OpenGL与红宝书第八版第一个程序配置

    本文档参考文献为<OpenGL编程指南>(原书第8版)中文版. 下面直接讲解笔者接触并初学OpenGL之路. 由于笔者学习方向的关系,有时接触到某些开源框架的时候,里面涉及到OpenGL. ...

  4. 关于在vs2013中配置opengl红宝书第八版环境

    转自 http://blog.csdn.net/qq821869798/article/details/45247241 本人刚开始学习opengl,买了一本opengl红宝书第八版, 第一个例子研究 ...

  5. JavaScript 红宝书第4版上市啦!「文末送几本给大家」

    文末有活动 人的一生中总要读几本经典书,在这个"经典"泛滥的年代,什么才是权威的代表,我想大概是一本的书的口碑,能积累下上佳口碑的书,往往也是能经得住时间推敲的.比如这本: 我相信 ...

  6. 用最简单的方法配置运行OpenGL红宝书第9版源码示例

    笔者真是苦逼啊,之前花了很多时间去学习"基于OpenGL的图形学"的开头部分,包括书本和老师的PPT.但是到自己尝试编译运行示例代码的时候真是困难重重.而且!在自己胡乱摸爬滚打终于 ...

  7. OpenGL编程指南 (红宝书 第八版) 样例代码配置问题汇总

    代码下载 环境配置问题glut 和 glew1 基本头文件和库文件配置2 以下是正文内容 第一个渲染程序Triangles3 第三章 03ch03_drawcommands4 本文是笔者自己在配置中遇 ...

  8. 【红宝书笔记精简版】 第二十四章 网络请求与远程资源

    目录 24.1 XMLHttpRequest 对象 24.1.1 使用 XHR 24.1.2 HTTP 头部 24.1.3 GET 请求 24.1.4 POST 请求 24.1.5 XMLHttpRe ...

  9. 【红宝书笔记精简版】第十二章 BOM

    目录 12.1 window 对象 12.1.1 Global 作用域 12.1.2 窗口关系 12.1.3 窗口位置与像素比 12.1.4 窗口大小 12.1.5 视口位置 12.1.6 导航与打开 ...

  10. 汇编语言 王爽 第四版 第二章 检测点2.2

    汇编语言 王爽 第四版 课后检测点 课后实验 持续更新~~ 检测点2.2 给定段地址为0001H,仅通过变化偏移地址寻址,CPU的寻址范围为 0010H 到 1000FH . 最小肯定是偏移地址为0, ...

最新文章

  1. 《庆余年》值得一看吗?Python告诉你谁在关注 | CSDN原力计划
  2. idle和python区别_Python的IDLE与命令lin的区别
  3. 代码逆流成河,深入C++如何又快又有效?
  4. Python爬虫实战八之利用Selenium抓取淘宝匿名旺旺
  5. (19)System Verilog模块设计示例
  6. 分布式SQL学习总结(2)——TiDB 的现在和未来
  7. php 怎么复制一个文件,php如何复制文件夹?
  8. 深掘工业互联网大数据五大维度
  9. C#编程(八十)---------- 异常类
  10. Deepracer 学了就能云驾驭赛车? Deepracer机器学习入门级干货分享!
  11. python字体描边_使用 python 将文泉驿字体导出为 fnt 格式的bitmap font
  12. 手机端和PC端开发区别
  13. layui 导航栏设置无鼠标停留特效_五款最受欢迎的热门wordpress开源主题 - 博客、导航...
  14. element ui 前台模板_element-ui 菜单模板封装(递归)
  15. 生产环境服务CPU飙升问题分析
  16. 为Android购买多个改装微信,安卓版微信带来超级重磅更新 微信终于开放账号ID修改功能喽(就是限制略多)...
  17. 离获得支付牌照还有多远?今日头条申请“字节支付”商标
  18. namesilo修改域名服务器,Namesilo 域名设置 A记录
  19. 文本记录任意时刻的ping值
  20. android sim卡应用程序,Android双SIM卡API

热门文章

  1. Spring定时器的配置
  2. 冰点文库下载器V3.2.4
  3. socket -- epoll模型
  4. html 数字加圆圈,word中圆圈数字,圆圈11怎么打
  5. 时间片轮转(RR)调度算法(详解版)
  6. NOPI修改xlsx文件内容,无法正常打开,提示文件格式或文件扩展名无效
  7. [Matlab科学计算] 绘制B样条基函数
  8. 【数据采集】-目前比较流行的几种数据采集方式
  9. 如何在IDM官网安装IDM谷歌插件?
  10. 深度置信网络(Deep belief network)matlab初解