理解异步和延迟
这是常见的前端面试题之一,考察面试者对 HTML、JS 和性能的掌握程度。
这是前端面试问答系列的第一题。如果你想提升准备水平或保持更新,可以考虑注册FrontendCamp。
该script
标签用于将 JavaScript 添加到 HTML 页面。它可以是内联脚本,也可以是外部脚本。
<body>
<!-- Some code before it -->
<script>
console.log("This is an inline script.");
</script>
<script src="https://example.com/external-script.js" />
<!-- Some code after it -->
</body>
在解析 HTML 时,如果浏览器遇到 script 标签,它将停止 HTML 解析并开始执行 JS 脚本。如果是内联脚本,它将立即开始执行;如果是外部脚本,它将被下载并执行。
在此期间,当 JS 脚本正在下载并执行时,HTML 解析会被阻止。只有浏览器执行完 JS 脚本后才能恢复。
你看出这里有什么问题了吗?这会给最终用户带来性能问题。如果我们有大量脚本,或者任何脚本执行时间很长,用户就会很长时间看不到页面内容。
为了解决这个问题,我们有两个属性:async
和defer
。
async
如果async
存在该属性,则脚本将在解析 HTML 的同时下载,并在可用时立即执行。
如果多个脚本使用该async
属性,则执行顺序可能与它们在 HTML 中出现的顺序不同。最先可用的脚本将首先执行。
<body>
<!-- Some code before it -->
<script async src="https://example.com/external-script.js" />
<!-- Some code after it -->
</body>
defer
如果defer
存在该属性,则脚本将与 HTML 解析并行下载(就像async
),但在 HTML 解析完成后和触发之前执行DOMContentLoaded
。
如果多个脚本使用该defer
属性,则执行顺序将会得到保持,这与 不同async
。
<body>
<!-- Some code before it -->
<script defer src="https://example.com/external-script.js" />
<!-- Some code after it -->
</body>
概括
- 两者
async
都defer
下载脚本而不阻止 HTML 解析。 async
脚本一旦可用就会立即执行。它可能会阻止 HTML 解析。defer
脚本将仅在 HTML 解析完成但在触发之前执行DOMContentLoaded
。async
如果执行顺序无关紧要且脚本不会修改 DOM,则使用。defer
如果执行顺序很重要或者脚本修改了 DOM,则使用。- 另请注意,这些属性不适用于内联脚本,即没有属性的脚本
src
。 - 如果同时添加了
async
和,则优先。defer
async