最近我看了不少教材,发现谈及在html文件中使用JavaScript的时候,基本都是概括为2种方法:
- 内联:在页面处插入script标签,其中JavaScript代码写在闭合标签script之间,例如下面这样:
<script>
console.log("Hello World!");
</script>
2.利用script标签的src属性,从外部引入,例如下面这样的:
<script src="myJavaScript.js"></script>
使用了src属性的script标签之间不能再在其中写功能性代码,因为浏览器会加载src所指向的.js文件的代码,而不会执行标签之间的代码,也就是说,假设我们写成下面这样
//html文件
<script src = “myJavaScript.js”>
console.log("内联的代码")
</script>
//myJavaScript.js文件
console.log("通过src引入的代码")
最终显示结果:内联的代码
上面就是在src标签内的使用了src属性,但是也在script标签之间写入了代码,但是最终控制台打印出来的是src属性引入的外部js文件中的代码。
在《JavaScript权威指南(第六版)》中,其实还提到了2种已经废弃的(准确说基本很难见到的引入方式:html事件处理程序和URL中的JavaScript引入)
1.html事件处理程序比较好理解,简单来说,就是通过事件的触发来完成某种响应,在这里,引入JavaScript代码就是我们的响应,比如下面这段代码:
<div onclick = " console.log('你点击了div')">
点击这里
</div>
用户通过点击div,触发了点击事件,想用的内容为打印出“你点击了div”字符串
2.URL后跟JavaScript:协议限定符
在html中,任何常规使用url的地方都可以用这种方法引入JavaScript代码,比如a标签的href,form标签的action,比如下面这样的:
<a href = "javascript:new Date().toLocalTimeString();">点击超链接</a>
点击后,浏览器会擦去当前文档并显示新文档**,
注意:
这里是擦除整个文档,而不是链接之间的文本内容。
以上的2种方法是web早期的使用,至今已经少有见到了,我们真正地还是使用script标签的src属性较多,因为,一来是外部引入src标签很方便于后期的维护和代码的重复使用,二来src属性可以实现jsonp等跨域
所以接下来,我们还是来好好看看script标签吧。
我们知道JavaScript是一门单线程的解释性语言(从上至下一行一行地解读代码),当客户端拿到文档时,从html开始往下加载,当遇到script标签时,浏览器默认先执行js脚本,然后再恢复对文档的解析和渲染。
这样就很容易出现一个问题,就是当我们使用外部引入的脚本时,在这个脚本彻底解析完之前,这个脚本后面的文档部分是不能被下载的,也就是说,如果这个脚本恰好非常庞大,解析时间需要很长,那么页面可能会出现空白,也就是我们常说的阻塞
script标签具备defer和async属性,它们的使用有以下限制:
1.只在外部脚本引入时有效
2.都是布尔属性,没有值
在不给script脚本添加defer或者async,我们的文档正常解析顺序是:
文档结构的解析→遇到script→停下文档的解析,开始加载script脚本文件→开始执行脚本文件→执行脚本文件完毕,继续后续的文档的解析
即同步
而defer和async同时异步加载了脚本,不同的是,二者的不同主要体现在执行脚本阶段,我用画图的方式说明:
对于脚本的加载,defer和async都会在后台开启一个新的线程,但是,defer对于脚本执行,必须在文档解析完成之后再进行,且是按照顺序执行。而async对于脚本执行,则是在脚本加载完后执行,且谁先加载完谁先执行