默认 同步加载: 脚本 <script>标签 默认用的都是 同步加载。
<script src="imagescript.js"></script>同步模式
又称 阻塞 模式,会阻止 浏览器的后续处理,停止了 后续的文件的 解析 ① 立即加载: 如果async,defer 两个属性 都不存在,则立即加载(获取) 脚本② 立即执行: 加载完成后, 立刻执行 脚本, 直到 脚本加载和执行 完成,才能进行 页面的解析/渲染/显示。这个时候,加载和执行 脚本, 都会 阻塞(打断)解析,多多少少 都会影响页面的显示速度.使用 同步加载和执行 的时机:
浏览器 需要采用 同步模式,一般因为 加载的 js文件中 有对 dom 的操作,如, 重定向 等 默认行为,所以同步才是 最安全的。把<script>标签 放在 </body>前的意义:
一般来说, <script> 都是放在 <head>中,来引用 外部脚本 js 文件的也会把要加载的 js文件 <script> 放到 </body>之前,使得js 文件 可 在 页面最后 加载,尽量减少 阻塞页面的渲染/显示。这样可以 先让页面显示出来.同步加载的 加载和执行 过程示例图
① 加载:不是 并行的,会打断 页面解析② 执行: 不是 并行的, 会打断 页面解析 加载和执行,都会 打断页面解析,影响 页面显示.脚本的 异步加载:
① 并行加载(获取): 对于脚本,如果有async属性,那么脚本 将在 页面解析过程中被 并行获取② 加载/下载完 立即执行: 并在 脚本文件加载(下载)完成 可用时(可能在 页面解析完成 之前) 进行执行。③ 执行 会打断解析: 加载 不打断页面解析,但 执行会打断 页面解析,记住,只是异步加载,执行 并不是异步的,还要回到原来的 流水线上.注意: 搭配 src 事项,异步加载, 仅限 外部脚本模块脚本(module scripts)的 异步加载
① 并行获取对于模块脚本,如果有 异步加载async属性,那么将在解析过程中 并行地获取 模块脚本及其所有依赖项② 下载完成 立即执行: 并且一旦模块脚本可用(可能在 页面解析完成之前),就会对其进行执行。 否则,模块脚本 及其依赖项 将在解析过程中 并行获取,并在页面完成解析后 进行执行。 注: 延迟执行 defer属性 对模块脚本 没有影响。异步加载async的 加载和执行 过程示例图
① 加载:是并行的,不影响 页面解析② 执行: 不是并行的, 会打断 页面解析 加载 不打断页面解析,执行 会打断页面解析.延迟执行: defer
① 并行获取: 如果 异步加载 async属性 不存在,而 延迟执行defer属性 存在,那么脚本将被 并行获取 加载/获取/下载,都是一个意思 ② 延迟执行: 并在页面完成解析后 进行执行。注意: 搭配 src 属性,延迟执行, 仅限 外部脚本延迟执行 defer的 加载和执行 过程示例图
① 加载:是并行的,不影响 页面解析② 执行: 不是并行的, 但不会打断 页面解析,因为是在 页面解析完成后 才执行的.加载和执行,都不会打断 页面解析.延迟执行的 使用时机
延迟执行: 有些 js代码 并不是 页面初始化的时候 就立刻需要的,而在 稍后的某些情况才需要的。那么一开始 并不执行 这些暂时不用的 js,而是在需要的时候 或稍后 再通过js 的控制来执行,也不会影响。根据 js 的需要时机 进行分类:
将 js 切分成许多模块,页面初始化时 只执行 需要立即执行的 js 可以使用 同步加载 ,可以放在head的script标签中其它 js ,可以延迟执行。 比如, 页面有大量不同的模块 组成,很多可能 暂时不用或根本就没用到。就像图片的延迟加载,在图片出现在可视区域内时(在滚动条下拉)才加载显示图片.延迟加载: 除了延迟执行,其实也可以设置 延迟加载,就是把 代码片段,写在 文档的底部,</body>的前面,这样 文档按顺序加载和解析的时候,到最后 才会加载这些代码片段.
注意: defer只是 延迟执行,并不是 延迟加载,在页面解析的同时,就并行加载了,也不会影响页面解析.
冲突事项:
用了defer不要使用 document.write() 方法;(为什么 ?因为涉及到 页面显示吗?延迟执行了,会影响页面显示?)⑴ 同步加载,异步加载async,延迟执行 defer的 加载 和 执行 示例图
绿色: 页面解析(渲染/显示)蓝色: 脚本 加载(下载/获取)红色: 脚本执行① 同步加载的 加载和执行 过程
加载:不是 并行的,会打断 页面解析执行: 不是 并行的, 会打断 页面解析 加载和执行,★ 都会 打断页面解析② 异步加载async的 加载和执行 过程
加载:是并行的,不影响 页面解析执行: 不是并行的, 会打断 页面解析 加载 不打断页面解析,★执行 会打断页面解析.③ 延迟执行 defer的 加载和执行 过程
加载:是并行的,不影响 页面解析执行: 不是并行的, 但不会打断 页面解析,因为是在 页面解析完成后 才执行的.加载和执行,★都不会 打断页面解析.⑵ 同时 指定 async,defer 属性: (行为回退,避免 阻塞行为)
行为 回退: 即使指定了 异步加载async属性,也可以指定 defer属性 回退到 延迟执行: 以使 仅支持 延迟执行defer(而不支持 异步加载async)的遗留Web浏览器 退回到 延迟执行defer行为,而不是 默认的阻塞行为。⑶ 多个脚本的 执行顺序:
① 同步加载 按顺序: 放置在<head>内 会阻塞<body>的渲染, 会出现白屏,按照顺序 立即执行几个脚本文件 ★ 按顺序: 放置在<body>底部 等<body>中的内容 渲染完毕后, 再加载, 顺序执行js <script>写在<body>底部,没有 兼容性问题,没有 白屏问题,没有 执行顺序问题. 是比较推荐的写法,很多网站都在使用,比如 淘宝网, MDN 网站等. ② 异步加载: 放置在<head>头部并使用async 先加载完毕的 先执行: 异步 并行加载资源,且加载完JS资源立即执行,并不会按 js 文件的顺序,谁快 谁先上 ③ 延迟执行: 放置在<head>头部并使用defer 按 顺序执行: 异步 并行加载资源,在 DOM 渲染后,即,页面解析完毕后, 再按顺序执行 jsHTML5 规范要求 脚本按照它们出现的 先后顺序执行,因此 第一个defer 延迟脚本, 会先 于第二个延迟脚本执行,而这两个脚本 会先于 DOMContentLoaded 事件执行。在实际应用当中,延迟执行的脚本 并不一定会按照 顺序执行,也不一定会在DOMContentLoad 时间触发前 执行,因此最好只包含一个延迟脚本。 ④ ★ 异步加载 和延迟执行: 放置在<head>头部, 并同时使用async和defer 表现和async一致不支持async的,支持defer的,会表现得和defer一样 异步加载 比延迟执行的 优先级高些. 这种方法,也是比较推荐的,同时兼容 支持async和defer 两个属性的 浏览器⑷ 仅限 外部脚本: 脚本<script>标签的 异步加载 async和 延迟执行defer,都必须搭配 src 属性,仅限 外部脚本 使用.