带你读红宝书-第二章-HTML中的JavaScript
如何将JavaScript插入到页面中?
我们通常使用<script>
元素来将脚本插入到页面中,不管是行内还是外部的脚本,他都会阻塞页面的渲染,你可以通过一些属性来改善,它的一些属性(?:表示可选属性):
- async?:只对外部脚本有效,立即下载这个脚本,但不能阻止其他资源和脚本的加载
- charset?:字符集编码,发展到现在可以直接忽略它的存在了
- crossorigin?:配置请求的CORS设置,。crossorigin="anonymous"配置文件请求不必设置凭据标志。crossorigin="use-credentials"设置凭据标志,意味着出站请求会包含凭据。
- defer?:只对外部脚本有效,表示脚本延迟到文档被完全解析和显示之后再执行.
- integrity?:可以使用指定的加密签名来验证资源的完整性.比如放置到CDN上的资源被恶意修改,那么它的签名不会匹配,页面将会抛出错误.
- language?:用来执行脚本的版本,如今已经废弃
- src?:外部脚本的路径
- type?:表示脚本的类型,按照惯例,这个值始终都是"text/javascript".如果这个至是
module
,则代表这个脚本是ES6模块,将可以再这个元素内使用import
,export
等关键字
行内jio本
来看一个有趣的
<script>
function sayScript() {
console.log("</script>");
}
</script>
这段代码看似没什么问题,实际上他会报错,因为脚本被提前结束了,如果想要正常输出"</script>"
,就需要对其进行转义啦
<script>
function sayScript() {
console.log("<\/script>");
}
</script>
外部jio本
<script src="example.js"></script>
使用了src属性后,不应该再使用行内样式的书写,通常行内的代码不会再次执行
❌bad example:
<script src="example.js">
console.log(123456)
</script>
src可以是一个网络请求,也可以是同域中的资源,当是一个url时,会发出一个get请求,不受同源策略的影响,但是其内执行的脚本受同源策略的影响
defer属性:讨论下脚本在页面中的位置
我们通常会将JavaScript脚本放置到页面底部,这是什么原因呢?我们前文提到过,脚本的执行还会阻塞页面的渲染,所以可以想象到,如果我们一个脚本所执行需要的耗时很长,而它被我们放置到了头部,那么再这个脚本执行完之前,一切渲染功能都停止了,用户看到的会是一个白页面,而将脚本执行完毕,渲染完毕,这个白页面的时间太长了,会让用户有一种感觉,那就是你的网站加载很慢~而放置到底部,就不会有这个问题了,即使用户提前看到的不是一个完整的应用,但是体验仍旧会好很多
如果你硬要将脚本放置到头部,那么也会有解决方案,那就是defer,他会等文档全部解析显示之后才会开始执行,但是他只对外部脚本有效,行内脚本会忽略这个属性.如果多个defer脚本,他们会按照放置的顺序执行.
async属性
它和defer基本一致,不同点:
- 它可能不会按照放置的顺序执行,所以你必须保证他们之间没有依赖关系
- 不阻塞浏览器的其他工作,即不用等待该脚本的下载和执行,也因此不应该出现操作dom的情况
你可以理解为这个属性专门开启了一条线程来负责该脚本的下载执行,完全不影响主线程的执行
动态脚本
我们可以使用DOM的createElement
这个api来创建一个动态插入到页面的脚本
let script = document.createElement('script');
script.src = 'gibberish.js';
script.async = false;
document.head.appendChild(script);
在将创建的元素插入到页面之前,是不会发出请求的,这种方式会默认以异步的方式加载脚本,所以我们手动设置了async
属性为false;这种方式对浏览器的预加载是不可见的,所以性能会严重影响,所以我们可以在头部添加
<link rel="preload" href="gibberish.js">
来告知浏览器将来我们会使用这些资源,请进行预加载
<noscript>
元素
用于在不支持的浏览器中,其中的内容会被当做文档解析;这点经常搞canvas
的人会比较有种熟悉感:
<canvas>你的浏览器不支持canvas</canvas>
小结
这个章节讨论了如何将JavaScript脚本插入到页面中,并介绍了他们之间的差异