<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title>async - 标签 - 菠菜眾長</title><link>https://lruihao.cn/tags/async/</link><description>async - 标签 - 菠菜眾長</description><generator>Hugo -- gohugo.io</generator><language>zh-CN</language><managingEditor>1024@lruihao.cn (Lruihao)</managingEditor><webMaster>1024@lruihao.cn (Lruihao)</webMaster><lastBuildDate>Sun, 08 Sep 2019 11:47:50 +0000</lastBuildDate><atom:link href="https://lruihao.cn/tags/async/" rel="self" type="application/rss+xml"/><item><title>script 的三种加载方式 (async, defer)</title><link>https://lruihao.cn/posts/async-defer/</link><pubDate>Sun, 08 Sep 2019 11:47:50 +0000</pubDate><author>Lruihao</author><guid>https://lruihao.cn/posts/async-defer/</guid><description><![CDATA[<div class="featured-image">
        <img src="/posts/async-defer/images/async_vs_defer.svg" referrerpolicy="no-referrer">
      </div><div class="details admonition note open">
    <div class="details-summary admonition-title">
      <i class="icon fa-solid fa-pencil-alt fa-fw" aria-hidden="true"></i>注意<i class="details-icon fa-solid fa-angle-right fa-fw" aria-hidden="true"></i>
    </div>
    <div class="details-content">
      <div class="admonition-content">JS 的加载分为两个部分：下载和执行。<br>
浏览器在执行 HTML 的时候如果遇到<code>&lt;script&gt;</code>时会停止页面的渲染，去下载和执行 js 的文件直接遇见<code>&lt;/scirpt&gt;</code>会继续渲染页面。故浏览器在执行 js 文件的时候浏览器表现为一片空白，为了解决这个问题 ECMAScript 定义了 defer 和 async 两个属性用于控制 JS 的下载和执行。</div>
    </div>
  </div>
<h2 id="不带任何属性">不带任何属性</h2>
<blockquote>
<p>同步模式，又称阻塞模式，我们平时使用的最多的一种方式。当浏览器解析到<code>&lt;script&gt;</code>标签时，浏览器会停止解析其后的内容，而优先下载脚本文件，并执行其中的代码，是个同步阻塞的过程。<br>
一般建议把<code>&lt;script&gt;</code>标签放在<code>&lt;body&gt;</code>结尾处，这样尽可能减少页面阻塞。<br>
而如果想要异步执行 script，则可以给其加上 async 或 defer 属性。</p>
</blockquote>
<div class="highlight" id="id-1"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span><span class="p">&gt;</span></span></span></code></pre></td></tr></table>
</div>
</div><h2 id="defer">defer</h2>
<blockquote>
<p>defer 属性在 HTML 解析期间异步下载文件，并且只在 HTML 解析完成后才执行它。对于 defer，我们可以理解是将外链的 js 放在了页面底部。js 的加载不会阻塞页面的渲染和资源的加载。不过 defer 会按照原本的 js 的顺序执行，<strong>所以如果前后有依赖关系的 js 可以放心使用。</strong></p>
</blockquote>
<div class="highlight" id="id-2"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span> <span class="na">defer</span><span class="p">&gt;</span></span></span></code></pre></td></tr></table>
</div>
</div><h2 id="async">async</h2>
<blockquote>
<p>async 属性会在 HTML 解析期间异步下载文件，并在完成下载后立即暂停 HTML 解析器去执行 script 中的代码。在执行过程中浏览器处于阻塞状态，响应不了任何需求。<strong>如果 js 前后有依赖性，用 async，就很有可能出错。</strong></p>
</blockquote>
<div class="highlight" id="id-3"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span> <span class="na">async</span><span class="p">&gt;</span></span></span></code></pre></td></tr></table>
</div>
</div><h2 id="区别">区别</h2>
<h3 id="相同点">相同点</h3>
<ol>
<li>加载文件时不阻塞页面渲染</li>
<li>对于 inline 的 script 无效（只适用有<code>src</code>的外部 js）</li>
<li>使用这两个属性的脚本中不能调用 document.write 方法</li>
<li>有脚本的 onload 的事件回调</li>
</ol>
<h3 id="区别点">区别点</h3>
<ol>
<li>html4.0 中定义了 defer；html5.0 中定义了 async</li>
<li>浏览器支持不同</li>
<li>每一个 async 属性的脚本都在它下载结束之后立刻执行，同时会在 window 的 load 事件之前执行。所以就有可能出现脚本执行顺序被打乱的情况；每一个 defer 属性的脚本都是在页面解析完毕之后，按照原本的顺序执行，同时会在 document 的 DOMContentLoaded 之前执行。</li>
</ol>
<h2 id="那么这三种方式各在什么情况下使用呢">那么这三种方式各在什么情况下使用呢？</h2>
<p>通常来说，尽可能使用<code>async</code>，然后是<code>defer</code>，最后不使用属性。
并遵循以下规则：</p>
<ul>
<li>如果脚本是模块化的，并且不依赖于任何脚本，则使用<code>async</code>。</li>
<li>如果脚本依赖于或依赖于另一个脚本，则使用<code>defer</code>。</li>
<li>如果脚本很小并且有<code>async</code>脚本依赖该脚本，则不加属性。</li>
</ul>
<h2 id="兼容性">兼容性</h2>
<ol>
<li>Internet Explorer 10、Firefox、Opera、Chrome 和 Safari 支持 async 属性。</li>
<li>所有主流浏览器都支持 defer 属性。</li>
</ol>
<h2 id="参考">参考</h2>
<ul>
<li><a href="https://www.growingwiththeweb.com/2014/02/async-vs-defer-attributes.html"target="_blank" rel="external nofollow noopener noreferrer">https://www.growingwiththeweb.com/2014/02/async-vs-defer-attributes.html<i class="fa-solid fa-external-link-alt fa-fw fa-xs ms-1 text-secondary" aria-hidden="true"></i></a></li>
<li><a href="https://www.jianshu.com/p/17dc82bf08f1"target="_blank" rel="external nofollow noopener noreferrer">https://www.jianshu.com/p/17dc82bf08f1<i class="fa-solid fa-external-link-alt fa-fw fa-xs ms-1 text-secondary" aria-hidden="true"></i></a></li>
</ul>]]></description></item></channel></rss>