第2章,HTML中的JavaScript

170 阅读6分钟

「这是我参与11月更文挑战的第1天,活动详情查看:2021最后一次更文挑战

本章学习内容:

  • 使用
  • 行内脚本与外部脚本的比较
  • 文档模式对JavaScript有什么影响
  • 确保JavaScript不可用时的用户体验
  1. 元素

    包含在

    外部引用代码只需要使用src这个属性,向其传入一个URL,指向包含JavaScript的文件:

    <script src="main.js"></script>
    

    与行内文件一样,解释外部JavaScript文件时,页面也会阻塞。

    此外,如果一个script既有src又有行内文件,此时的script只会解释引入文件,不会解释行内文件。

    浏览器在解析资源的时候,会向src属性指定的路径发送一个get请求,以获得相应的资源,并假定这个资源就是JavaScript文件,所以这个请求不会受到浏览器同源策略的限制,但是如果确认时JavaScript文件时,其返回和执行就会受到限制。并且也会受到来自父页面HTTP/HTTPS协议的限制。

    一个外部引用的文件会当做所加载页面的一部分加载解释,这使得我们可以从不同的域分发JavaScript。此时如果引用外域的文件则需要考虑改文件会不会被篡改。以保证页面正常显示。

    只要是通过script引用的文件,都会按照其在页面出现的顺序依次解释。前提是他们都没有defer和async属性。此时后面的代码必须等待前面的解释完才能开始解释。

    1. 标签位置

      过去script都被放在了head内部:

      <!DOCTYPE html>
      <html>
      	<head>
      	<title>script</title>
      		<script src="1.js"></script>
      		<script src="2.js"></script>
      	</head>
      </html>
      

      这样做是为了将CSS和JavaScript集中起来,不过这样就会导致在JavaScript没有全部下载完成之前,是不会被有页面显示的。这通常会导致实现的显示延迟。所以此后的script通常会被放到元素之后。

      <!DOCTYPE html>
      <html>
      	<head>
      		<title>script</title>
      	</head>
      	<body>
      		<script src="1.js"></script>
      		<script src="2.js"></script>
      	</body>
      </html>
      
    2. 推迟执行脚本

      script中有一个defer属性,这个属性这个脚本会在整个页面执行完毕之后再执行。在

      <!DOCTYPE html>
      <html>
      	<head>
      		<title>script</title>
      		<script defer src="1.js"></script>
      		<script defer src="2.js"></script>
      	</head>
      </html>
      

      虽然1.js和2.js写在了head中,但是他们会等到浏览器解析到之后才会执行,并且按照出现的顺序执行。两者都会在DOMContentLoaded事件之前执行。但是实际上defer脚本不一定会按照我们想要的顺序执行,所以一个页面最好只有一个defer脚本。

      defer属性从IE4、Firefox 3.5、Safari 5 和 Chrome 7 开始的,所以其他浏览器会忽略,因此最好还是写在最后。

    3. 异步执行脚本

      从改变脚本处理方式上看,async和defer类似。都只使用与外部,通知浏览器立即下载,稍后执行。但是async不能保证其执行顺序。async属性主要是告诉浏览器,不必等脚本下载和执行完再加载画面,也不必等该脚本执行完再执行其他脚本,因此,异步脚本不应出现在加载期修改DOM异步脚本会保证在load事件之前,但不保证在DOMContentLoaded的前后执行。

    4. 动态加载脚本

      除了script,JavaScript还可以使用DOM API 加载脚本。只需要创建一个script元素加入到DOM即可:

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

      当然,在添加HTMLElement之前是不会发送请求的,默认情况下,这种方式创建的script都是异步加载。相当于添加了async。不过虽然所有浏览器都支持createElement()方法,堵车不都支持async方法。所以可以明确使用同步方法

      let script = document.createElement('script');
      script.src="main.js";
      script.async="false";
      document.head.appendChild(script);
      

      但是这种方式对于浏览器预加载是不可见的,会严重影响资源队列的优先级,可能会严重影响性能。如果需要让预加载器知道他们,需要头部声明:

      <link rel="preload" href="main.js"></link>
      
    5. XHTML中的变化

      可扩展超文本标记语言(XHTML)是将HTML作为XML应用重新包装的结果。在XHTML中,JavaScript必须指定type属性为"text/javascript",但是XHTML已经退出了历史舞台。

  2. 行内代码和外部文件

    虽然script可以允许在页面内写入JavaScript,也可以通过外部引用,但是在日常实践的时候,我们会尽可能的将JavaScript代码写在外部文件中,不知道大家有没有想过这是外什么。

    • 可维护性:JavaScript代码如果分散到多个HTML页面,会导致维护困难。而且用一个目录保存所有的JavaScript代码会更利于维护。
    • 缓存:浏览器会根据特定的设置缓存所有外部链接的JavaScript文件,这意味着如果两个页面都用到同一个文件的话,并不需要下载两次。
    • 适应未来:通过把JavaScript放到外部,就不需要考虑前文中的XHTML。因为外部文件对于HTML和XHTML都是一样的。

    所以更加轻量的,独立的JavaScript组件向客户端送达脚本是更具有优势的。

  3. 文档模式

    即可以使用DOCTYPE切换文档模式。最初文档模式只有混杂模式和标准模式。前者让IE能学习IE5(支持非标准特性),后者让IE具有兼容标准的行为。这两种模式最主要的区别在于CSS渲染上,但是对于JavaScript也有一些关联影响,被称为副作用,记住这个副作用,后面会多次提到。

    随着浏览器的发展,文档模式又出现了:准标准模式。这种模式下浏览器支持多标准的特性,但是有没有规定的那么严格。主要区别在于对待图片元素周围的空白(表格中最为明显)

    混杂模式可以不使用DOCTYPE声明作为开关,但是这并不合理,因为这样在各个浏览器中差异巨大,导致没有了浏览器一致性。

    标准模式和准标准模式的差别就非常小了,文档模式的检测也不会区分,所以我们常说的标准模式就是除混杂模式之外的模式。

  4. 元素

    虽然现在的浏览器100%都支持了JavaScript,但是还会有禁用JavaScript的浏览器,这时就需要,该元素可以包含任何可以出现在中的HTML元素,script除外。

    只有在下列两种情况下,浏览器才会显示其中内容:

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

    满足其一,中的内容就会被渲染,反之就不会。

    总结:

    • script有两种解释方式,8中属性。
    • 外部文件必须在src中写入url,并且需要注意同源问题。
    • script可以放到head中也可以放到body中,但是推荐放到body底部,因为script执行会阻塞页面。并且如果没有defer或者async属性的话,会按照出现顺序解释。
    • JavaScript推荐写成外部文件。利于维护,缓存,兼容XHTML。
    • 文档模式用于支持一些非标准模式,除混杂模式都称为标准模式。
    • 在不支持脚本的浏览器使用,可以解释脚本