为什么<script>标签应该尽可能放到<body>标签的底部?
因为脚本执行过程中可能会修改页面内容,Js 的下载和执行会阻塞页面其它资源的下载,多数浏览器使用单一进程来处理 UI 刷新和 Js 脚本执行。
扩展属性 defer async 是什么,有什么作用?
defer 指明本元素所含的脚本不会修改 DOM,因此代码能安全地延迟执行。对应的 Js 文件将在页面解析到 sctipt 标签时开始下载,但不会执行,会在 onload 事件处理器执行之前被调用。defer 的 script 可以和页面的其它资源并行下载。(defer 属性仅当 src 属性声明时才有效)
async 用于异步加载脚本。defer 与 async 的相同点是采用并行下载,在下载过程中不会产生阻塞。
区别是 async 是在加载完成之后自动执行,defer 需要等待页面完成后执行。
什么是动态脚本元素?如何创建?
使用 DOM 方法可以动态创建<script>元素。无论何时启动下载,文件的下载和执行过程不会阻塞页面的其它进程,是最通用的无阻塞加载解决方式。
function loadScript (url, callback) {
var script = document.createElement('script')
script.type = 'text/javascript'
script.onload = function () {
callback()
// 需要确保脚本下载就绪,才能被其它地方调用
}
script.src = url
document.getElementsByTagName('head')[0].appendChild(script)
}
XMLHttpRequest 脚本注入怎么用?有什么局限性?
var xhr = new XMLHttpRequest()
xhr.open('get', 'test.js', true)
xhr.onreadystatechange = function () {
if(xhr.readyState === 4) {
if (xhr.status >=200 && xhr.status < 30 || xhr.status == 304) {
var script = document.createElement('script')
script.type = 'text/javascript'
script.text = xhr.responseText
document.getElementsByTagName('head')[0].appendChild(script)
}
}
}
xhr.send(null)
主要局限性是不能跨域请求,意味着不能从 CDN 下载。大型 web 应用通常不采用 XHR 脚本注入。