笔记:红宝书 ——《JavaScript高级程序设计》 :第2章 HTML中的JavaScript

在JavaScript早期,网景公司的工作人员希望在将JavaScript引入HTML页面的同时,不会导致页面在其他浏览器中渲染初问题

最终他们达成了向网页中引入通用脚本能力的共识

当初他们的工作得到了保留,并且最终形成了HTML规范

2.1 < script>元素

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

  1. 其有以下8个属性
属性名状态作用使用
async可选立即开始下载文件,但不能阻止其他页面动作,比如下载资源或等待其他脚本加载外部脚本
charset可选使用src属性指定的代码字符集少用,大多浏览器不在乎它的值
crossorigin可选配置相关请求的CORS(跨源资源共享)设置,
crossorigin=“anonymous”配置文件请求不必设置凭据标志
crossorigin=“use-credentials”设置凭据标志,意味着出站请求会包含凭据
默认不使用CORS
defer可选表示脚本可以延迟到文档完全被解析和显示之后再执行外部脚本,IE7及更早版本,行内也有效
integrity可选允许对比接收到的资源和指定的加密签名以验证子资源完整性(SRI,Subresource Integrity),如果接收到的资源的签名与这个属性指定的签名不匹配,则页面会报错,脚本不会执行。这个属性可以用于确保内容分发网络(CDN,Content Delivery Network)不会提供恶意内容
language废弃最初用于表示代码块中的脚本语言(如:”JavaScript“、”JavaScript1.2“,”VBScript“)大多数浏览器都会忽略这个属性
src可选表示包含要执行的代码的外部文件
type可选代替language,表示代码块中脚本语言的内容类型(MIME类型)

type中:按照惯例,这个值始终都是”text/javascript“,尽管”text/javascript“和”text/ecmascript“都已经废弃了,

javascript文件的MIME类型通常是”application/x-javascript“,不过给type这个值有可能导致脚本被忽略。

在非IE浏览器中有效的其他值还有”application/javascript“和”application/javascript“。

如果这个值是module,则代码会被当成es6模块,只有这时候代码中才能出现import和export关键字

  1. 使用<script>的方式
  • 通过它直接在网页中嵌入JavaScript代码

    • 直接把代码放在<script>元素中就行
    • <script>元素中的代码被计算完成前,页面的其余内容不会被加载,也不会被显示
    • 注意代码中不能出现</script>字符串,否则会报错
    • if要避免上述问题,只需转义字符“\”
  • 通过它在网页中包含外部JavaScript文件

    • 必须使用src属性
    • 与解释行内一样,解释外部JavaScript文件时,页面会阻塞(阻塞时间包含下载文件的时间)
    • 在XHTML中,可以<script src='excample.js' />,但其是无效的HTML,有些浏览器不能正常处理
    • 其url指向的资源可以与其HTML页面不在同一个域中
      • 例如<script src='http://www.somewhere.com/afile.js'></script>
      • 浏览器在解析这个资源时,会向src属性指定的路径发送一个GET请求,以取得相应资源
      • 这个初始请求不受浏览器同源策略限制
      • 返回并被执行的JavaScript受限制
      • 这个请求仍然受父页面HTTP/HTTPS协议的限制
    • 来自外部域的代码会被当成加载它的页面的一部分来加载和解释
      • 这个能力可以让我们通过不同的域分发JavaScript
      • 若引用了别人服务器上的文件,要确保文件不会被替换

    使用了src属性的<script>元素不应该在标签中再包含其他JavaScript代码,否则浏览器只会下载执行脚本文件,从而忽略行内代码

2.1.1 标签位置

  • 放在<head></head>标签内(过去)

    意味着必须把所有的JavaScript代码都下载、解析和解释完成后,才能开始渲染页面,

    若有很多JavaScript文件的页面,会有明显的延迟

  • <body>元素中的页面内容后面(现代web应用程序)

2.1.2 推迟执行脚本

HTML4.01定义了defer属性,表示脚本在执行时不会改变页面的结构。即脚本会被延迟到整个页面都解析完毕后再运行

告诉浏览器立即下载,但延迟执行

<head>
	<script defer src='example.js'></script>
    <!-- if XHTML 
	defer="defer"
	-->
</head>

HTML5规范要求脚本应该按照他们出现的顺序执行,且均会在DOMContentLoaded事件之前执行;

但实际中,推迟执行的脚本不一定总会按照顺序执行或者再DOMContentLoaded事件之前执行;

因此最好只包含一个这样的脚本。

defer属性的支持时从IE4、Firefox3.5、Safari5和Chrome7开始的。其他浏览器会忽略这个属性,所以还是把要延迟的脚本放在页面底部比较好

2.1.3 异步执行脚本

HTML5定义了async属性,其与defer类似,都只适用于外部脚本,都会告诉浏览器立即开始下载。

async不能保证他们按照他们出现的次序执行

<head>
    <script async src='example1.js'></script>
    <script async src='example2.js'></script>
    <!-- if XHTML 
	async="async"
	-->
</head>

告诉浏览器,不必等脚本下载和执行完后再加载页面,同样也不必等到该异步脚本下载和执行后再加载其他脚本,所以异步脚本不应该在加载期间修改DOM。

异步脚本保证会在load事件前执行,但可能会在DOMContentLoaded之前/后;

使用其也会告诉页面,你不会使用document.write;

Firefox3.6、Safari5和Chrome7支持异步脚本;

2.1.4 动态加载脚本

因为JavaScript可以使用DOM API,所以通过向DOM中动态添加script元素同样可以加载指定的脚本

let script = document.createElement('script'); //创建
script.src='gibbarish.js';
//默认以这种方式创建的`script`是异步加载的,相当于添加了async,但可能会有问题
//因为所有浏览器支持createElement()方法,但不是所有浏览器都支持async属性
//所以为了统一动态脚本的加载行为,可以明确将其设置为同步加载
script.async=false;
document.head.appendChild(script);//添加到页面上

以这种方式获取的资源对浏览器预加载器是不可见的,会影响它们在资源获取队列中的优先级。根据应用程序的工作方式以及怎么使用,这种方式可能会严重影响性能

要想让预加载器知道这些动态请求文件的存在,可以在文档头部显示声明它们:

<link rel='preload' href='gibberish.js'>

2.1.5 XHTML中的变化

可扩展性文本标记语言(XHTML,Extensible HyperText Markup Language)是将HTML作为XML的应用重新包装的结果。

在XTML中使用JavaScript必须指定type=text/javascript,HTML则可以没有。

XHTML虽然已经退出历史舞台,但实践中偶尔可能也会遇到遗留代码

在XHTML中编写代码比较严格,

  • 在编写JavaScript时,小于号<会被解释成一个标签的开始,并且由于作为开始标签的小于号后面不能有空格,所以if(a < b)这样的代码会报错;以下是避免这种错误的方法:

    • 把所有小于号<都替换成对应的HTML实体形式&lt;,即if(a &lt; b)

    • 把所有代码都包含到一个CDATA块中

      在XHTML/XML中,CDATA块表示文档中可以包含任意文本的区块,其内容不作为标签来解析,因此可以在其中包含任意字符

      <script type='text/javascript'><![CDATA[
              function compare(a , b){
                  if(a < b){
                      console.log("a < b");
                  }...
              }
          ]]></script>
      

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

    所以CDATA比如使用JavaScript注释来抵消:

    <script type='text/javascript'>
        //<![CDATA[
            function compare(a , b){
                if(a < b){
                    console.log("a < b");
                }...
            }
        //]]>
    </script>
    

    这种格式使用于所有现代浏览器,它不仅可以通过XHTML验证,而且对XHTML之前的浏览器也能优雅地降级

    2.1.6 废弃的语法

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

    • 在不支持JavaScript的浏览器(特别是Mosaic)中会把<script>元素的内容输出到页面上,解决方案是把脚本代码块包含在一个HTML注释中

    <script><!--
    	function sayHi(){
            console.log("Hi!");
        }
    //--></script>
    

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

    但其实这种格式以及不再必要,而且不应该使用了。在XHTML模式下,这种格式会导致脚本被忽略,因为代码处于有效的XML注释当中。

2.2 行内代码和外部文件

推荐使用外部文件:

  • 可维护性
  • 缓存
    • 浏览器会根据特定的设置缓存所有外部链接的JavaScript文件
    • 若两个页面引用到同一个文件,则该文件只需下载一次,意味着页面加载更快
  • 适应未来
    • 不必考虑用XHTML或前面提到的注释
    • 外部JavaScript的语法在HTML和XHTML中是一样的

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

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

2.3 文档模式

IE5.5发明了文档模式,即可以使用doctype切换文档;

最初的文档模式有两种:混杂模式标准模式

这两种模式的区别只体现在通过CSS渲染的内容方面,对JavaScript也有一些关联影响,或称为副作用。

后来又出现了第3种文档模式:准标准模式

这种模式下的浏览器支持很多标准的特性,但是没有标准规定的那么严格;

主要区别在如何对待图片元素周围的空白(在表格中使用图片时最明显)

  1. 混杂模式:在所有浏览器中都以省略文档开头的doctype声明作为开关,这种约定不合理,因为混杂模式在不同浏览器中的差异很大,不使用黑科技基本上就没有浏览器一致性可言。

  2. 标准模式:通过下列几种文档类型声明开启

    • <!-- HTML 4.01 Strict -->
      <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" 
      "http://www.w3.org/TR/html4/strict.dtd">
      
    • <!-- XHTML 1.0 Strict -->
      <!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" 
      "http://www.w3.org/TR/xhtml1/DTD/xhtml-strict.dtd">
      
    • <!-- HTML5 -->
      <!DOCTYPE html> 
      
  3. 准标准模式:通过过滤性文档类型(Transitional)和框架集文档类型(Frameset)来触发

    • <!-- HTML 4.01 Transitional -->
      <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
      "http://www.w3.org/TR/html4/loose.dtd">
      
    • <!-- HTML 4.01 Frameset -->
      <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" 
      "http://www.w3.org/TR/html4/frameset.dtd">
      
    • <!-- XHTML 4.01 Transitional -->
      <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
      "http://www.w3.org/TR/xhtml1/DTD/xhtml-transitional.dtd">
      
    • <!-- XHTML 1.0 Frameset -->
      <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" 
      "http://www.w3.org/TR/xhtml1/xhtml1-frameset.dtd">
      

准标准模式和标准模式非常接近,很少需要区分,而本书后面所说的标准模式,指的是除混杂模式之外的模式

2.4 < noscript>元素

针对早期浏览器不支持JavaScript的问题,需要一个页面优雅降级的处理方案。

<noscript>元素即用于给不支持JavaScript的浏览器提供替代内容。

虽然先浏览器已经100%支持JavaScript,但对于禁用JavaScript的浏览器来说,这个元素仍然有它的用处

<noscript>元素可以包含任何可以出现在<body>中的html元素(除<script>);

当满足如下任一条件时,浏览器将显示包含在<noscript>的内容:

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

2.5 小结

JavaScript是通过<script>元素插入到html页面中的:

  • 要包含外部JavaScript文件,必须将src属性设置为要包含文件的url。文件可以跟网页在同一台服务器上,也可以位于完全不同的域
  • 所有<script>元素会依照它们在网页中出现的次序被解释,在不使用deferasync时,包含在<script>的代码必须严格按次序解释
  • 对不推迟执行的脚本,浏览器必须解释完位于<script>元素的代码,然后才能继续渲染页面的剩余部分。为此,通常把此元素放到页面末尾
  • 可以使用defer属性把脚本推迟到文档渲染完毕后再执行。推迟脚本的原则上按照次序执行
  • 可以使用async属性表示不需要等待其他脚本,同时也不阻塞文档渲染,即异步加载。异步脚本不能保证按照次序执行
  • 通过使用<noscript>元素,可以指定在浏览器不支持脚本时显示的内容。如果浏览器支持,则<noscript>元素中的任何内容都不会被渲染
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值