了解异步和延迟的HTML属性

111 阅读8分钟

了解异步和延迟的HTML属性

脚本组件是一个重要的HTML标签。它指的是在网页中运行的可执行代码或数据。

下面是一个script 标签的例子。

<script src='javcascriptcode.js'></script> 
<!-- the src attribute refers to an executable code or data-->

一个script 标签可以指向一个外部源,甚至包含可执行代码。

在某些情况下,可执行数据可能比HTML文件大。这意味着在下载和处理HTML文件时会有延迟。

浏览器必须先下载和处理script 标签的内容,然后再渲染网页的其他部分。

async 和 属性有助于减少执行脚本标签中代码时的延迟。defer

这些元素对提高网页性能至关重要。它们有利于增强用户体验。

在本教程中,你将了解Asyncdefer脚本属性。

目标

在这篇文章中,你将学习

  • 浏览器如何解析HTML。
  • 什么是asyncdefer
  • 如何使用asyncdefer
  • asyncawait之间的异同。

前提条件

要跟上进度,你需要

  • 对[HTML]有一些基本的了解。
  • 对[Javascript]有一些基本的了解。
  • 一个代码编辑器。我们将使用[VS Code]。

关于脚本标签的误解

大多数人认为,script 标签应该在关闭的body 标签之前,如下图所示。

<head></head>
<body>
    <H1>My Website</H1>
    <p>Welcome to my Portfolio</p>
    <script src=’javascriptcode.js’></script><!-- script tag before the closing tag -->
</body> <!-- closing body tag -->

这种假设是由于浏览器解析(加载)HTML的方式造成的。

然而,你可以把script 标签放在HTML文档的任何地方。例如,你可以把它放在header 标签内,或者紧接着开头的body 标签之后,如下图所示。

<head>
    <script src=’javascriptcode.js’></script> <!-- script tag within the header tag -->
</head>
<body>
    <H1> MY Website</H1>
    <p>Welcome to my Portfolio</p>
</body>

浏览器如何解析HTML代码

在我们深入研究asyncdefer属性之前,你需要了解浏览器如何解析HTML。

解析是指分析程序文件并将其转换为便于运行环境(浏览器)操作的格式。这里,一个程序文件可以是一个HTML文件,也可以是一个JavaScript文件。

对HTML文件的解析通常包括标记化和树状结构。

标记化是将HTML的开头标签、结尾标签、属性名称和值划分为单元,称为tokens

树状结构包括使用标记建立文档对象模型(DOM)

当浏览器解析HTML代码并遇到一个script 标签时,浏览器会暂停执行过程。

然后,浏览器下载该script 的内容,继续解析HTML代码。

但是,如果你有一个HTML文件,在header 标签或body 标签内有许多script 标签。这些标签可能会导致解析HTML文件时出现明显的延迟。

出现这种延迟是因为浏览器在每个脚本标签中暂停了对HTML文件的解析。然后,浏览器会请求script 标签的内容。因此,script 标签下面的HTML内容被屏蔽了。

在下载完script 标签的内容后,HTML文件的解析就可以继续进行。

下面的图片让我们对正常的HTML解析有了更好的了解。

Normal-script-execution

如上图所示。

  1. 一旦浏览器解析HTML并遇到一个脚本标签,就会暂停HTML解析。
  2. 然后,浏览器在继续进行HTML解析之前,会获取(下载)并执行该脚本。

一个HTML文件中的许多script 标签可能会导致明显的延迟。对于拥有快速互联网连接的最终用户来说,这个问题可能不会被注意到。

然而,大多数终端用户的网络连接速度较慢,因此可能会注意到这种延迟。我们可以使用deferasync属性来解决这个问题。

<script src='' async></script>
<script src='' defer></script>

了解async和defer属性

在文章的这一部分,你将了解什么是async和defer。

Async和defer属性是script 标签的布尔值,可以消除解析器阻塞的JavaScript。

解析器阻塞JavaScript是一个过程,浏览器在加载和执行script 标签的内容时,会阻止或暂停HTML代码。

延迟

用通俗的话说,defer ,意思是推迟到以后的时间。下面是一个将defer 作为script 标签属性的例子。

<h1>...content before script...</h1>
<script defer src="script.js"></script>
<!-- visible immediately -->
<p>...content after script...</p>

当一个script 标签包含像上面这样的defer ,它就会通知浏览器。

  • 当它接触到脚本时,不要阻止HTML文件的解析。浏览器继续构建DOM,所以script 标签之后的内容是可见的。

  • 要在后台加载脚本。

  • 暂停DOMContentLoaded 事件,直到脚本被完全加载和评估。

  • 按顺序执行脚本。它维护script 标签的顺序。例如,long-script.js 将在short-script.js 之前被首先加载。

<script defer src="long-script.js"></script>
<script defer src="short-script.js"></script>

在上面的例子中,short-script.js 可能因为其大小而先下载。但由于脚本标签中的defer 属性,浏览器将不会执行short-script.js ,直到long-script.js 下载并执行。

script 标签没有src属性时,defer属性就没有作用。

下面的图片提供了对defer属性的直观理解。

defer-script-execution

从上面的图片来看。

一旦浏览器解析了HTML并遇到了一个脚本标签。浏览器就会在解析HTML的同时获取(下载)并执行该脚本。

它不会暂停HTML的解析。脚本会在HTML完全解析后执行。

异步

我们从 "异步 "这个词中得到了async,这意味着事件不是在同一时间发生的。

当你在script 标签上添加布尔脚本属性,async 。它通知了浏览器。

  • 当它接触到脚本时,不要阻止HTML文件的解析。浏览器会继续构建DOM,所以script 标签之后的内容是可见的。

  • 在后台加载脚本,并在脚本加载完毕后执行。带有async 属性的脚本在执行前不需要等待DOMContentLoaded

异步脚本是独立于其他脚本和DOM的,如下面的例子所示。

<p>...content before scripts...</p>
    <script>
    document.addEventListener(‘DOMContentLoaded’, () => alert(“DOM is visible!”));
    </script>
    <script async src=”long-script.js”></script>
    <script async src="short-script.js"></script>
<p>...content after scripts...</p>

在上面的例子中。

  • 浏览器立即显示该页面。Async不会阻塞DOMContentLoaded 事件。它在HTML内容完全加载之前就显示'DOM是可见的'。

异步脚本通常遵循load-first 的原则。下面的图片提供了一个对async属性的直观理解。

Async-Execution

异步脚本与可用的DOM元素一起工作。即使在DOM没有被完全解析的情况下。

例如,如果在一个HTML文件中有25000 按钮,而只有1000 按钮加载,async将在1000 按钮上触发DOMCOntentLoaded

Async不会等待其余的24000 按钮再触发DOMContentLoaded 事件。

开始使用

让我们建立一个项目来巩固我们到目前为止所学到的知识。

在这个项目中,你将创建25000 按钮。你将看到deferasync属性是如何执行的。

第1步 - 创建一个项目文件夹

我们需要创建一个新的文件夹,它将包含项目的HTML文件。

在你的代码编辑器中导航到命令行或集成终端。键入下面的命令。

mkdir buttons

使用下面的命令导航到该文件夹。

cd buttons

第2步 - 创建一个HTML文件

buttons 文件夹中创建一个buttons.html文件。将下面的代码添加到生成的HTML文件中。

<head>
    <script src=”defer.js" defer></script>
    <script src="async.js" async></script>
</head>
<body>
    <div class="container">
    <!-- 25000 buttons -->
    </div>
</body>

在上面的HTML代码中,我们有两个脚本。第一个脚本带有defers属性,第二个脚本带有async属性。

第3步 - 添加按钮

要创建25000 按钮,把这个链接放在评论下面的**buttons.html** 里面。

然后按tab键。

<head>
    <script src="defer.js" defer></script>
    <script src="async.js" async></script>
</head>
<body>
    <div class="container">
    <!-- 25000 buttons -->
    button{click}*250000 //press tab after typing this
    </div>
</body>

第4步 - 创建JavaScript文件(defer.js)

让我们写一些JavaScript代码来选择HTML代码中的所有按钮。请按照以下说明。

按钮文件夹中创建一个新的JavaScript文件。把这个JavaScript文件命名为defer.js

复制下面的代码并粘贴到defer.js 文件中。

// Defer script code
let deferButton = document.querySelectorAll(‘button’);
console.log(`Defer script button count: ${deferButton.length}`);

在上面的代码中,我们选择了HTML文件中的所有buttons 。然后我们将buttons length ,并记录到控制台。

第5步 - 创建JavaScript文件(async.js)

创建一个async.js文件,在async.js文件中添加以下代码。

// Async script code
let asyncButton = document.querySelectorAll(‘button’);
console.log(`Async script button count: ${asyncButton.length}`);

在上面的代码中,我们选择了HTML文件中的所有buttons 。然后我们将按钮的长度记录到控制台。

测试该项目

在浏览器中打开该项目。然后按照下面的说明,打开浏览器的控制台。

  1. f12键,打开开发者工具。

  2. 在开发者工具的顶部,点击控制台。

在控制台中,你会看到如下图所示的东西。

image

从上面的图片来看。

  • 异步不等待DOM完全加载。异步脚本在其执行时可用的buttons ,即3957上触发DOMContentLoaded

  • Defer等待DOM元素完全加载。Defer脚本在等待DOMContentLoaded 后选择了所有25000 按钮。

async和defer之间的区别

在本节中,我们将看看asyncdefer 之间的区别。

延迟异步
加载(执行)顺序脚本标签的出现顺序很重要。脚本标签的出现顺序并不重要。
DOMContentLoaded在HTML文件被完全加载和解析后执行,就在DOMContentloaded之前。可以在DOMContentloaded之前或之后执行。

何时使用async或defer

什么时候使用async和defer是一个很难做出的决定。然而,我们可以在以下情况下使用defer

  • 脚本依赖于整个DOM。
  • 当你的脚本依赖于另一个脚本时,例如,当使用jQuery或其他外部库或框架时。请确保在你的脚本之前调用外部库或框架。
  • 当脚本的执行顺序很重要时。

你可以使用async

  • 脚本是独立于DOM的,例如广告或google analytics。
  • 脚本的相对执行顺序并不重要,例如在广告中。

总结

你已经学会了浏览器如何解析HTML。我们还讨论了async和defer标签属性、它们的区别和使用情况。

Async和defer属性可以消除解析阻塞的JavaScript。