script元素
<script>
元素有8个属性
(1)async:可选 立即开始下载脚本 不能阻止其他页面动作 比如下载资源或等待其他脚本加载 只对外部脚本文件有效
(2)charset:可选 使用src属性执行的代码字符集 这个属性很少使用
(3)crossorigin:可选 配置相关请求的CORS(跨资源共享)设置 默认不适用CORS crossorigin="anonymous"配置文件请求不必设置凭据标识 crossorigin="use-credentials"设置凭据标志 意味着出站请求会包含凭据
(4)defer:可选 表示脚本可以延迟到文档完全被解析和显示之后再执行 只对外部脚本文件有效
(5)integrity:可选 允许比对接收到的资源和指定的加密签名以验证子资源完整性SRI 如果接收到的资源的签名与这个属性指定的签名不匹配 则页面会报错 脚本不会执行 这个属性可以用于确保CDN不会提供恶意内容
(6)language:废弃
(7)src:可选 包含要执行的代码的外部文件
(8)type:可选 代替language 表示代码块中脚本语言的内容类型(MIME类型) 如果值为module 则代码会被当成ES6模块 而且只有这时代码中才能出现import和export关键字- 使用
<script>
的方式:
(1)使用它直接在网页中嵌入JS代码
<script>
这里写JS代码 注意这里的JS代码中不能出现字符串'</script>'
浏览器解析行内脚本时看到字符串'</script>' 会将其当成结束标签</script>
解决:使用转义字符'<\/script>'
</script>
(2)使用它引入外部JS文件(推荐)
<script src='外部JS文件的URL 这个URL的扩展名可以不是.js 如果不是 一定要确保服务器能返回正确的媒体类型(MIME) 因为服务器根据文件扩展名来确定响应的正确MIME类型'>
不能在这里写JS代码 就算写了也只会下载并执行src指向的脚本文件 而忽略这里的JS代码
</script>
- 浏览器在解析这个资源时 会向src指定的路径发一个GET请求 以获取相应资源(假设是个JS文件) 这个初始的GET请求不受同源策略的限制 但返回并被执行的JS文件受限制 当然这个请求仍然受父页面HTTP/HTTPS协议的限制
- 获取到的资源可能被黑客替换 资源可能包含恶意代码 使用
<script>
元素的integrity
属性可以避免这个问题 - 不管获取到的是什么资源 只要资源所在
<script>
标签没有使用defer
或async
属性 浏览器都会按照<script>
在页面中出现的顺序依次解释
<script>
元素中的代码被计算完成之前 页面的其余内容不会被加载 也不会被显示 页面会阻塞<script></script>
与<script />
:前者是HTML文档中的语法 后者是XHTML的 后者不能在HTML中使用 因为有些浏览器不能正常处理 如IE
标签位置
如果把<script src="example.js"></script>
放在<head></head>
中 那么必须把所有JS代码都下载 解析 解释完成后 才能开始渲染页面 页面在浏览器解析到<body>
时开始渲染 这会导致页面渲染明显延迟 在此期间浏览器窗口完全空白 为了解决这个问题 把<script src="example.js"></script>
放在</body>
后面
推迟执行脚本
defer
:脚本在执行时不会改变页面的结构 即脚本会被延迟到整个页面都解析完毕后(解析到</html>
后)再执行 这个属性相当于告诉浏览器立即下载 延迟执行- 延迟执行的脚本不一定会按顺序执行 或在DOMContentLoaded事件之前执行 因此最好只包含一个这样的脚本
- H5规定:只对外部脚本文件有效 会忽略行内脚本的
defer
属性 - 存在兼容性问题 建议把延迟执行的脚本放在页面底部
- XHTML文档指定
defer
属性:defer="defer"
异步执行脚本
async
:告诉浏览器 立即下载 但是不必等脚本下载和执行玩后再加载页面 同样 也不必等该异步脚本下载和执行完成后再加载其他脚本 所以 一部脚本不应该子加载期间修改DOM- H5规定:只对外部脚本文件有效 会忽略行内脚本的
async
属性 async
属性的脚本不一定按照他们出现的顺序执行 并且可能在DOMContentLoaded事件之前或之后执行 但一定会在页面的load事件前执行- 存在兼容性问题
async
属性会告诉页面你不会使用document.write
因为document.write
会在未close的文档流中追加内容 而async
属性的脚本什么时候执行是不确定的 所以你追加的内容出现在哪个位置也是不确定的 所以用async
时不用document.write
- XHTML文档指定
defer
属性:async="async"
动态加载脚本
通过向DOM中动态添加script元素同样可以加载指定的脚本 只需要创建一个script元素并将其添加到DOM中
let script = document.createElement('script');
script.src = 'example.js';
document.head.appendChild(script);
- 在把HTMLElement元素添加到DOM且执行到这段代码前不会发送请求
- 默认情况下 以这种方式创建的
<script>
元素是以异步方式加载的 相当于添加了async
属性 但由于有的浏览器不支持async
属性 所以可以更改默认值 将其设置为同步加载
let script = document.createElement('script');
script.src = 'example.js';
script.async = 'false';// 新增
document.head.appendChild(script);
- 使用动态加载脚本的方式获取资源 资源对浏览器预加载器是不可见的 这会影响资源再资源获取队列中的优先级 从而影响性能 为了让预加载器知道这些动态请求文件的存在 我们可以在文档头部显示声明它们
<link rel="preload" href="example.js">
XHTML中的变化
- XHTML:可扩展超文本标记语言 将HTML作为XML的应用重新包装的结果 在XHTML中使用JS必须指定
type="text/javascript"
- 在XHTML中写代码规则更严格
<script type="text/javascript">
function compare(a, b){
if(a < b) console.log("a小于b")
else console.log("a不小于b")
}
</script>
XHTML会把上述代码中的<
解释成一个标签的开始 并且由于标签开始的<
后面不能有空格 所以上面的代码会报错 解决办法:
(1)将<
替换为<
(2)将JS代码放在CDATA块中 在XHTML及XML中 CDATA块表示文档中可以包含任意文本的区块 CDATA块中的内容不会作为标签解析 但是CDATA块存在兼容性问题 所以CDATA标记必须使用JS注释来抵消 这样CDATA块才能适用于所有浏览器(这种语法已废弃)
<script type="text/javascript">
//<![CDATA[
function compare(a, b){
if(a < b) console.log("a小于b")
else console.log("a不小于b")
}
//]]>
</script>
- XHTML模式会在页面的MIME类型被指定为
"application/xhtml+xml"
时触发 但并不是所有浏览器都支持以这种方式送达的XHTML
文档模式
noscript元素
- 给不支持JS的浏览器提供替代内容
<noscript>
元素可以包含任何可以出现在<body>
中的HTML元素 除了<script>
- 在下面两种情况下 浏览器才会显示包含在
<noscript>
中的内容
(1)浏览器不支持<script>
(2)浏览器对<script>
的支持被关闭
任何一个内容被满足 包含在<noscript>
中的内容就会被渲染