你设置defer、async和我script有什么关系

1,186 阅读4分钟

面试官面前我唯唯诺诺,阿菜面前我重拳出击

从前有座山,山上有座庙,庙里有个小和尚和老和尚,

老和尚问道:"你知道script标签吗?它..."

还没等老和尚问完,小和尚放下手中的木鱼:“师傅,stop,回答完上次for循环和forEach的区别, 你也没让我下山啊,虽然我知道script分为外链引入和内联,我也知道放在body的最后有利于页面的载入”

老和尚连忙制止道:“为师想问你,你知道script上面其实还有defer和async两个属性吗,以及他们的区别”

小和尚拿起无处安放的木鱼并支支吾吾到:"我都把script放到body的尾部, 你还想要人家怎样啦"

老和尚【猝】

HTML中script的那些破事之defer、async

路人甲:“众所周知,script标签上除了经常用到的一个属性src,还有defer、async”;

众人皆摇头

路人甲:“那我直说了, 据史料W3C[1]记载,

  • async 规定异步执行脚本(仅适用于外部脚本)。
  • defer 规定是否对脚本执行进行延迟,直到页面加载为止。(仅适用外部脚本)“

突然从人群中窜出一位叫阿菜的精神小伙:“口说无凭啊”

众人纷纷随身附和道;

不得已路人甲从口袋里拿出了编辑器和浏览器:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script  src="../js/examp1.js"></script> <!-- console.log('1娃')-->
    <script async src="../js/examp2.js"></script> <!-- console.log('2娃')-->
</head>
<body>
    <header>
        我是header
    </header>
    <main>
        我是主题, 为什么不写div,因为我要语义化
    </main>
    <footer>
        一双脚
    </footer>
    <script >
        document.addEventListener('DOMContentLoaded', function() {
            console.log('主体')
        })
    </script>
    <script src="../js/examp3.js"></script> <!-- console.log('3娃')-->
</body>
</html>

结果:

阿菜心想:”你这厮将examp1.js和examp2.js放在head中,不怕遭雷劈吗浏览器解析慢吗?“

常规操作都是将js文件放在body的尾部,不影响document的解析,提升用户体验;

async 不阻塞,但随意插队 ☆☆

async 标签,不阻止document解析,并行加载外部js文件(加载完成后立即执行) 可能在DOMContentLoaded事件前,也可能在后

<script async src="../js/examp1.js"></script> <!-- console.log('1娃')-->
<script src="../js/examp2.js"></script> <!-- console.log('2娃')-->

看到了吧,除了1娃的位置不确定,其他始终是2娃 > 主体 > 3娃

此时如果2娃打不过蛇精,召唤1娃,有可能gg;

这些引入的js文件其中有相互依赖比如:

这种情况的话,有可能报错$.ajax undefined

<script async src="../js/examp1.js"></script> <!-- console.log('1娃')-->
<script async src="../js/examp2.js"></script> <!-- console.log('2娃')-->

这种就更热闹了,就像《西游记》出现孙行者、者行孙、行者孙、奔波灞、霸波奔之类的情况

defer 不阻塞, 排队执行 ☆☆☆☆

那这机灵又顽皮的async不可控,那就看看defer又能带来怎样的惊喜

  • 同样不阻止document解析,同时加载外部js文件
  • 不同的是在js文件加载完成之后,并不会立即执行,而是看看自己前后, 按先后顺序执行,且一定是在DOMContentLoaded事件之前执行
<script src="../js/examp1.js"></script> <!-- console.log('1娃')-->
<script defer src="../js/examp2.js"></script> <!-- console.log('2娃')-->

结果:

一个script同时有async、defer, async起作用,defer无效

<script src="../js/examp1.js"></script> <!-- console.log('1娃')-->
<script defer async src="../js/examp2.js"></script> <!-- console.log('2娃')-->

结果:

内联的script标签想用async、defer, 没门

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="../js/examp1.js"></script> <!-- console.log('1娃')-->
    <script src="../js/examp2.js"></script> <!-- console.log('2娃')-->
    <script async>
        console.log('内联async')
    </script>
</head>

没有效果的,defer也没有效果,

众人如梦初醒,路人甲捋了捋自己那不存在的胡子并露出满意的笑容,只见那位远去少年的身影说声:“放到body底部不香吗?” 菜终究是菜啊!

回头看

  1. async、defer都不会阻塞document的解析,
  2. defer加载完成,会在按js文件引入顺序执行,且在DOMContentLoaded之前
  3. async加载完成,立即执行,不管这个DOMContentLoaded,在前在后都有可能

引用1、彻底搞懂async & defer

Reference

[1]

W3school: HTMLScript标签。

本文使用 mdnice 排版