[浏览器知识点] 脚本defer、async & CORS

404 阅读2分钟

defer

  • 具有defer特性的脚本不会阻塞页面。
<p>...content before script...</p>

<script defer src="https://javascript.info/article/script-async-defer/long.js?speed=1"></script>

<!-- 立即可见 -->
<p>...content after script...</p>
  • 具有 defer 特性的脚本总是要等到 DOM 解析完毕,但在 DOMContentLoaded 事件之前执行。
<p>...content before scripts...</p>

<script>
  document.addEventListener('DOMContentLoaded', () => alert("DOM ready after defer!"));
</script>

<script defer src="https://javascript.info/article/script-async-defer/long.js?speed=1"></script>

<p>...content after scripts...</p>

1. 页面内容立即显示。
2. `DOMContentLoaded`事件处理程序等待具有 defer 特性的脚本执行完成。
它仅在脚本下载且执行结束后才会被触发。
  • 具有 defer 特性的脚本以“文档顺序”执行。
<script defer src="https://javascript.info/article/script-async-defer/long.js"></script>
<script defer src="https://javascript.info/article/script-async-defer/small.js"></script>

defer特性除了告诉浏览器“不要阻塞页面”之外,还可以确保脚本执行的相对顺序。因此,即使 small.js 先加载完成,它也需要等到 long.js 执行结束才会被执行。

  • defer 特性仅适用于外部脚本,如果 <script> 脚本没有 src,则会忽略 defer 特性。

async

<p>...content before scripts...</p>

<script>
  document.addEventListener('DOMContentLoaded', () => alert("DOM ready!"));
</script>

<script async src="https://javascript.info/article/script-async-defer/long.js"></script>
<script async src="https://javascript.info/article/script-async-defer/small.js"></script>

<p>...content after scripts...</p>
  • 具有async特性的脚本不会阻塞页面。
  • DOMContentLoaded 可能在 async 之前或之后触发,不能保证谁先谁后。
  • 异步脚本以“加载优先”的顺序执行。

在实际开发中:

  1. defer 用于需要整个 DOM 的脚本,和/或脚本的相对执行顺序很重要的时候。
  2. async 用于独立脚本,例如计数器或广告,这些脚本的相对执行顺序无关紧要。

跨源策略(CORS)

源(origin): 域(domain)、端口(port)、协议(protocol)的组合。

跨源请求:那些发送到其他域(即使是子域)、协议或端口的请求,需要来自远程端的特殊header。

这个策略被称为“CORS”:跨源资源共享(Cross-Origin Resource Sharing)。

从浏览器角度来看,有两种跨源请求:“简单”请求其他请求

简单请求必须满足:

  • 方法:GET,POST 或 HEAD。
  • header —— 我们仅能设置:
    • Accept
    • Accept-Language
    • Content-Language
    • Content-Type 的值为 application/x-www-form-urlencoded,multipart/form-data 或 text/plain。

对于简单请求:

  • → 浏览器发送带有源的 Origin header。
  • ← 对于没有凭据的请求(默认不发送),服务器应该设置:
    • Access-Control-Allow-Origin 为 * 或与 Origin 的值相同
  • ← 对于具有凭据的请求,服务器应该设置:
    • Access-Control-Allow-Origin 值与 Origin 的相同
    • Access-Control-Allow-Credentials 为 true 此外,要授予 JavaScript 访问除 Cache-Control,Content-Language,Content-Type,Expires,Last-Modified 或 Pragma 外的任何 response header 的权限,服务器应该在 header Access-Control-Expose-Headers 中列出允许的那些 header。 image.png

对于非简单请求,会在请求之前发出初步“预检”请求:

  • → 浏览器将具有以下 header 的 OPTIONS 请求发送到相同的 URL:
    • Access-Control-Request-Method 有请求方法。
    • Access-Control-Request-Headers 以逗号分隔的“非简单” header 列表。
  • ← 服务器应该响应状态码为 200 和 header:
    • Access-Control-Allow-Methods 带有允许的方法的列表,
    • Access-Control-Allow-Headers 带有允许的 header 的列表,
    • Access-Control-Max-Age 带有指定缓存权限的秒数。
  • 然后,发出实际请求,应用先前的“简单”方案。 image.png

参见