重学JavaScript系列——(二)HTML中的JavaScript

重学JavaScript系列——(二)HTML中的JavaScript

博主以扎实JavaScript基础为目的,以《JavaScript高级程序设计(第四版)》为核心参考资料,以一个“复习者”的角度有针对性地来创作这期专栏。文章加入了博主的很多思考和开发经验,关注初学JavaScript时容易忽略的地方,着重总结了ECMAScript新标准知识点的特性和应用场景。最终,本专栏将覆盖完整的JavaScript知识体系,以辅佐各路豪杰在开发路上的稳步前进。

专栏传送门:https://blog.csdn.net/huoyihengyuan/category_10586561.html


将JavaScript引入网页,首先就要解决它和网页主导语言HTML的关系。在JavaScript早期,网景公司的工作人员希望在将JavaScript引入HTML的同时,不会导致页面在其他浏览器中出现渲染问题。当今,我们以这种机制为基础实现了更多的东西。当初他们的很多工作被保留到HTML规范中,致敬网景公司。

2.1 script标签

将JavaScript引入到HTML中的主要方法就是使用<script>元素。这个元素最初由网景公司创造,最早在Netscape中实现。

<script>元素主要属性:

属性描述
src可选。要执行的代码外部文件。
type可选。表示代码块中脚本语言的内容类型(也称MIME类型)。如果这个值被设为“module”,则代码会被当作ES6模块,有且只有这时,代码中才能出现import和export关键字。
async可选。表示应该立即下载文件,但不能阻止页面其他动作,比如下载资源或等待其他脚本加载。只对外部文件有效。
defer可选。表示文档解析和显示完成后再执行脚本。只对外部文件有效。
crossorigin可选。配置相关请求的CORS。普通的<script>标签只向window.onerror反馈少量信息(“Script Error”),如果设置了crossorigin属性,并在服务端设置了Access-Control-Allow-Origin响应头,就可以在window.onerror中反馈更详细的日志信息
integrity可选。比对制定的加密签名和下载的资源,以验证子资源完整性(SRI,Subresource Integrity)。如果不匹配,则页面报错,脚本不会执行,可以确保CDN不会提供恶意内容。
language可选。~~最初表示代码块中脚本语言。~~大多数浏览器都会忽略这个属性,不应该再使用它。
charset可选。~~使用src属性指定的代码字符集。~~很少用,大多数浏览器不在乎它的值。

使用<script>的方式主要有两种:通过它直接在网页中JavaScript代码,和通过它在网页中包含外部JavaScript代码。

其实,<script>中的代码会被从上到下解释,在代码被计算完成之前,页面的其余内容不会被加载,也不会被显示。

在使用行内JavaScript代码时,代码中不能出现</script>,想要避免这个问题,只需要个转义字符“\”即可.

console.log('<\/script>');

按照惯例,外部JavaScript的文件扩展名是“.js”,但这不是必须的,因为浏览器不会检查JavaScript文件扩展名。这就方便了服务器端脚本语言动态生成JavaScript代码,以及在浏览器中将JavaScript扩展语言(如TypeScript、React的JSX)转译为JavaScript。

另外,使用了src属性的<script>元素不应该再在标签内包含其他JavaScript代码。如果二者都存在的话,则浏览器会忽略行内代码。

我们或许利用过<script>的src不受浏览器同源策略的影响的特性,去做一些跨域的操作。最常见的场景就是直接拷贝某些包含CDN链接的开源库<script src=“http://www.cdn.xxx.com/xxx.min.JavaScript”>,从而方便将之引入到我们的html文件中。然而,引用了放在别人服务器上的JavaScript文件要格外小心,因为恶意的程序员可能会把对应的文件替换成恶意代码。<script>的integrity属性可以防范这个问题,但这个属性不是所有浏览器都支持。为了保证网站的安全性,还是推荐将代码放到自己的服务器上。

当然,在没有使用defer和ansyc属性的情况下,浏览器总会按照<script>在页面中出现的顺序依次解释它们。

2.1.1 标签位置

在页面加载过程中,当在浏览器解析到<body>时才开始渲染,在此之前浏览器窗口显示空白。

过去,所有<script>元素被放到<head>中,对于需要很多JavaScript的页面,用户会感觉到明显的渲染延迟,即出现白屏期。为了解决这个问题,现代Web应用程序通常将所有的JavaScript引用放到body内容主体之后、</body>标签之前。这样一来,页面在处理JavaScript代码之前完全渲染页面,用户会感觉页面加载更快了,因为浏览器显示的空白时间缩短了。

2.1.2 推迟执行脚本

在<script>元素上设置defer属性,会告诉浏览器立即下载对应文件,但会将脚本的执行延迟到</html>解析完成后,即整个页面解析完成之后。但会在DOMContentLoaded事件之前执行。

HTML5明确规定,defer只对外部脚本文件有效,但在不支持HTML5的浏览器上,则会表现出旧的行为。所以,为了让代码尽可能地兼容更多的浏览器,我们还是把这些需要延迟执行的代码放到页面底部比较好。

对于XHTML文档,指定defer的属性应该写成defer=“defer”的形式。

2.1.3 异步执行脚本

<script>中还有个async属性,和defer类似,都会告诉浏览器立即下载,并且也只适用于外部脚本。不过与defer不同的是,async标记的脚本并不能保证它们出现的次序。

对于XHTML文档,指定async的属性应该写成async=“async”的形式。

关于defer和async的执行区间可以参考这张图:

在这里插入图片描述

2.1.4 动态加载脚本

除了在设计页面时直接引入<script>标签,还可以动态加载脚本。

一种常见的解决跨域问题的方案jsonp,就是利用<script>等标签不受同源策略影响的机制进行解决跨域问题。通过DOM API动态添加<script>元素的方式就是动态加载脚本,只要创建一个<script>元素并将其添加到DOM即可。

let script = document.createElement('script')
script.src = 'A.js'
document.body.appendChild(script)

默认情况下,通过这种方式创建的<script>元素是以异步方式加载的,相当于添加了async属性,但不是所有浏览器都支持async属性,因此要统一动态脚本的加载行为,可以明确其设置为同步加载:

let script = document.createElement('script')
script.src = 'A.js'
script.async = false
document.body.appendChild(script)

但仅仅是这样的动态加载脚本有个性能问题。这种方式获取的资源对浏览器预加载器是不可见的,这会影响它们在资源获取队列的优先级。想要预加载器知道这些动态请求文件的存在,可以在文件头部显式声明它们:

<link rel="preload" href="A.js">

2.1.5 XHTML中的变化

XHTML是将HTML作为XML重新包装的结果,可以理解为“严格的HTML”。虽然它已退出历史舞台,但在实践中偶尔会遇到遗留代码,所以这里简单提一下。

XHTML在语法上我们要注意更多的细节。比如,在<script>里小于号<会被解释成一个标签的开始,但实际上我们只是想做条件判断。虽然这种情况也可以用“符号实体(如&lt;)”或“CDATA块”方案来解决,但如果不支持CDATA的浏览器又要考虑如何优雅的降级。

程序的编写应该越来越简单,而不是越来越复杂。但在当时的情况下,XHTML的过渡作用,证明了一代人在完善这套体系时,做出了不断的努力和创新,致敬!

2.1.6 废弃的语法

来回顾一下历史。

历史上存在这样一种情况:过去某些浏览器不支持JavaScript,所以如果含有<script>的代码会被打印到页面上,破坏页面外观。

对于这种代码,当时有一个解决方案:

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

这样,不支持JavaScript的浏览器就会忽略<script>标签里面的内容,支持JavaScript的浏览器就会运行脚本代码。

2.2 行内代码和外部文件

我们虽然可以直接在HTML中嵌入JavaScript代码,但大多数情况下最佳实践还是通过外部文件进行引入。理由如下:

  • 可维护性——开发者可以统一管理JavaScript代码,结构也可以更加清晰。
  • 缓存——浏览器的特定缓存设置,对于多个页面同一个文件,只需要下载一次。
  • 适应未来——外部文件引入的方式,使我们不必考虑XHTML的某些问题,而且越来越多的工具或IDE也可以让我们对单独的JavaScript文件做出更多定制化工作。比如“ESlint代码规范校正”。

2.3 文档模式

文档模式是给浏览器看的,告诉浏览器要以什么标准来解析文档。

最初的文档模式有两种混杂模式和标准模式,后来又出现了准标准模式。

不过,现在只需要记得,在当前主流的实际开发中,我们始终使用HTML5的规范:

<!DOCTYPE html>
声明对大小写不敏感。不过一定要放到

<html>之前,作为文本第一行。

2.4 noscript标签

<noscript>会出现在某些平台HTML文件的初始化代码中,在当浏览器不支持脚本或者是脚本被禁用时,显示<noscript>里面的内容。

虽然当前浏览器几乎已经100%支持JavaScript了,脚本被禁用的情况也少之又少,但是它还是有存在的必要的。毕竟,我们是一群严谨的程序员,当然也可以留下个友好的彩蛋。

小结

在HTML中加入JavaScript脚本代码,相当于为HTML静态页面赋予了“神经”。为了更有安全感地驾驭这套“神经冲动”,我们通过<script>的defer或async控制它的下载队列,并聊了聊一些安全性和兼容性问题。

如何在网页中引入代码,取决于我们这些开发者的习惯。但为了匹配更完美的结果,我们会使用一些细节方面的最佳实践方案。

这一期是HTML中的JavaScript,也介绍了一部分历史上引入JavaScript的变迁过程。作为最前线的一批开发者,我们可以用最新的标准和规范,来为推动前端发展贡献一点自己的力量。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值