异步加载和延迟加载
When loading a script on an HTML page, you need to be careful not to harm the loading performance of the page.
在HTML页面上加载脚本时,需要注意不要损害页面的加载性能。
A script is traditionally included in the page in this way:
传统上,脚本是通过以下方式包含在页面中的:
<script src="script.js"></script>
whenever the HTML parser finds this line, a request will be made to fetch the script, and the script is executed.
只要HTML解析器发现这一行,就会请求获取脚本,并执行脚本。
Once this process is done, the parsing can resume, and the rest of the HTML can be analyzed.
完成此过程后,就可以继续进行解析,然后可以分析其余HTML。
As you can imagine, this operation can have a huge impact on the loading time of the page.
您可以想象,此操作可能会对页面的加载时间产生巨大影响。
If the script takes a little longer to load than expected, for example if the network is a bit slow or if you’re on a mobile device and the connection is a bit sloppy, the visitor will likely see a blank page until the script is loaded and executed.
如果脚本的加载时间比预期的要长一点,例如,如果网络有点慢,或者您使用的是移动设备,并且连接有点草率,那么访问者可能会看到空白页,直到脚本被加载为止。加载并执行。
位置很重要
(
The position matters
)
When you first learn HTML, you’re told script tags live in the
<head>
tag:
初学HTML时,系统会告诉您脚本标记位于
<head>
标记中:
<html>
<head>
<title>Title</title>
<script src="script.js"></script>
</head>
<body>
...
</body>
</html>
As I told you earlier, when the parser finds this line, it goes to fetch the script and executes it.
Then
, after it’s done with this task, it goes on to parse the body.
正如我之前告诉您的那样,当解析器找到这一行时,它将去获取脚本并执行它。
然后
,完成此任务后,它将继续解析正文。
This is bad because there is a lot of delay introduced. A very common solution to this issue is to put the
script
tag at the bottom of the page, just before the closing
</body>
tag.
这很糟糕,因为引入了很多延迟。 解决此问题的一种非常常见的方法是将
script
标记放在页面底部,紧接
</body>
标记之前。
In doing so, the script is loaded and executed after all the page is already parsed and loaded, which is a
huge improvement
over the
head
alternative.
这样,在所有页面都已经解析并加载之后,脚本便被加载并执行,这是
head
方法的
巨大改进
。
This is the best thing you can do if you need to support older browsers that do not support two relatively recent features of HTML:
async
and
defer
.
如果需要支持不支持HTML的两个相对较新的功能的较旧的浏览器,这就是最好的选择:
async
和
defer
。
异步和延迟
(
Async and Defer
)
Both async and defer are boolean attributes. Their usage is similar:
异步和延迟都是布尔属性。 它们的用法类似:
<script async src="script.js"></script>
<script defer src="script.js"></script>
if you specify both,
async
takes precedence on modern browsers, while older browsers that support
defer
but not
async
will fallback to
defer
.
如果同时指定两者,则
async
在现代浏览器中优先,而支持
defer
但不支持
async
旧版浏览器将回退到
defer
。
For the support table, check caniuse.com for async
https://caniuse.com/#feat=script-async
and for defer
https://caniuse.com/#feat=script-defer
对于支持表,请检查caniuse.com以获取异步
https://caniuse.com/#feat=script-async
和推迟
https://caniuse.com/#feat=script-defer
These attributes only make sense when using the script in the
head
portion of the page, and they are useless if you put the script in the
body
footer like we saw above.
这些属性仅在页面
head
使用脚本时才有意义,如果将脚本放在如上所示的
body
页脚中,它们将无用。
性能比较
(
Performance comparison
)
头部无延迟或异步
(
No defer or async, in the head
)
Here’s how a page loads a script without either defer or async, put in the
head
portion of the page:
这是页面加载到页面
head
不延迟或异步的脚本的方式:
The parsing is paused until the script is fetched, and executed. Once this is done, parsing resumes.
暂停解析,直到提取并执行脚本。 完成此操作后,将继续解析。
体内没有延迟或异步
(
No defer or async, in the body
)
Here’s how a page loads a script without defer or async, put at the end of the
body
tag, just before it closes:
以下是页面加载时没有延迟或异步的脚本的方式,该脚本放置在
body
标签的末尾,即关闭之前:
The parsing is done without any pauses, and when it finishes, the script is fetched, and executed. Parsing is done before the script is even downloaded, so the page appears to the user way before the previous example.
解析过程没有任何暂停,完成后,将提取并执行脚本。 解析是在脚本下载完成之前完成的,因此该页面以用户的方式出现在上一个示例之前。
与异步,在头上
(
With async, in the head
)
Here’s how a page loads a script with
async
, put in the
head
tag:
这是页面如何使用
head
标签放置带有
async
的脚本的方式:
The script is fetched asynchronously, and when it’s ready the HTML parsing is paused to execute the script, then it’s resumed.
脚本是异步获取的,准备就绪后,HTML解析将暂停以执行脚本,然后将其恢复。
推迟,在头上
(
With defer, in the head
)
Here’s how a page loads a script with
defer
, put in the
head
tag:
这是页面加载带有
head
标签的
defer
脚本的方式:
The script is fetched asynchronously, and it’s executed only after the HTML parsing is done.
该脚本是异步获取的,只有在HTML解析完成后才执行。
Parsing finishes just like when we put the script at the end of the
body
tag, but overall the script execution finishes well before, because the script has been downloaded in parallel with the HTML parsing.
解析完成时就像将脚本放在
body
标签的末尾一样,但是总体而言脚本执行早于完成,因为脚本是与HTML解析并行下载的。
So this is the winning solution in terms of speed 🏆
所以这是速度方面的制胜法宝
阻止解析
(
Blocking parsing
)
async
blocks the parsing of the page while
defer
does not.
async
阻止页面解析,而
defer
不阻止。
阻止渲染
(
Blocking rendering
)
Neither
async
nor
defer
guarantee anything on blocking rendering. This is up to you and your script (for example, making sure your scripts run after the
onLoad
) event.
async
或
defer
都不保证阻止渲染。 这取决于您和您的脚本(例如,确保脚本在
onLoad
之后运行)事件。
dom互动
(
domInteractive
)
Scripts marked
defer
are executed right after the
domInteractive
event, which happens after the HTML is loaded, parsed and the
DOM
is built.
标记为
defer
脚本在
domInteractive
事件后
domInteractive
执行,该事件在HTML加载,解析并构建
DOM
之后发生。
CSS and images at this point are still to be parsed and loaded.
此时CSS和图像仍然需要解析和加载。
Once this is done, the browser will emit the
domComplete
event, and then
onLoad
.
完成此操作后,浏览器将发出
domComplete
事件,然后发出
onLoad
。
domInteractive
is important because its timing is recognized as a measure of perceived loading speed.
See the MDN
for more.
domInteractive
非常重要,因为它的时间被认为是感知加载速度的度量。
有关
更多信息,
请参见MDN
。
保持秩序
(
Keeping things in order
)
Another case pro
defer
: scripts marked
async
are executed in casual order, when they become available. Scripts marked
defer
are executed (after parsing completes) in the order which they are defined in the markup.
另一个
defer
情况:标记为
async
脚本在可用时以随意顺序执行。 标记为
defer
脚本(在解析完成之后)将按照标记中定义的顺序执行。
告诉我最好的方法
(
Just tell me the best way
)
The best thing to do to speed up your page loading when using scripts is to put them in the
head
, and add a
defer
attribute to your
script
tag:
使用脚本时,加快页面加载速度的最佳方法是将它们放在
head
,并在
script
标签中添加
defer
属性:
<script defer src="script.js"></script>
This is the scenario that triggers the faster
domInteractive
event.
这是触发更快的
domInteractive
事件的方案。
Considering the pros of
defer
, is seems a better choice over
async
in a variety of scenarios.
在各种情况下,考虑
defer
的优点似乎是优于
async
的更好选择。
Unless you are fine with delaying the first render of the page, make sure that when the page is parsed the JavaScript you want is already executed.
除非可以延迟页面的第一次渲染,否则请确保在解析页面时,所需JavaScript已经执行。
异步加载和延迟加载