script标签中async和defer区别

405 阅读3分钟

1.async

async的意思是异步加载,也就是说,html解析的时候,如果遇到具有async的script标签,可以一边继续向下解析html模版,另一边开始加载script标签中的资源,互不影响。但是如果async标签中的资源异步加载完成之后,html需要立即执行。

2.defer

defer是延迟执行,也就是在async的基础上,控制它加载完成后的具体的执行时间。也算是弥补async不能控制加载完成后的执行时间。这里的defer也是异步加载,加载完成后在html模版解析结束后执行。 盗用一张图: image.png 所以,defer和async的区别在于,两个加载完成之后何时执行。但是浏览器中具有defer的script脚本在文档解析完成过后执行,但是在DOMContentLoaded之前。

3.使用场景

如果项目中的cdn加载非常慢,并且这个script资源不影响dom的构建,可以使用defer。这样就不会影响dom的构建。之前做的项目中遇到一个jsbrideg资源的二次加载。 原因分析:查看浏览器(timing)中接口请求和响应时间:发现接口调用时间中,connection start时间是2min,响应等待时间是75ms 问题原因:

可能原因1:客户端原因-浏览器中同域名最大请求数量为6,在大象app客户端中浏览器的请求上限数量降低,导致客户端发送请求发送的等待时间很慢

可能原因2: (实际原因)浏览器“缓存锁”问题segmentfault.com/a/119000003… 业务场景: 一个项目中引用了另一个项目,这两个项目中都同时需要jsbridge资源(项目中都需要jsbridge中的API),而两个项目又存在依赖了关系。所以在父项目初始化时候加载了jsbridge的cdn,然后接着加载子项目,子项目中又继续加载jsbridge的cdn,这个时候子项目加载cdn速度非常慢。 这是因为第一个tab请求 jsbrideg时, 属于jsbrideg的cache处于写操作,而第二个请求的时候,发现已经有‘jsbrideg’的cdn链接处于写的状态,但是自己有需要读。这个时候读写之间的切换需要有个足够的安全时间。所以此时第二个读操作会被挂起。 解决方案:script中使用defer或者禁止使用缓存no-cache, no-store,那么就不存在读写的切换。

no-cache 和 no-store 都是 HTTP 协议头 Cache-Control 的值。区别是:

  • no-store(不存储)
    彻底禁用缓冲,所有内容都不会被缓存到缓存或临时文件中。
  • no-cache(协商缓存)
    在浏览器使用缓存前,会往返对比 ETag,如果 ETag 没变,返回 304,则使用缓存; 使用no-cache的目的就是为了防止从缓存中获取过期的资源

除了 no-cache 和 no-store,Cache-Control 头的取值还有:

  • public 所有内容都将被缓存(客户端和代理服务器都可缓存)
  • private 内容只缓存到私有缓存中(仅客户端可以缓存,代理服务器不可缓存)
  • max-age=xxx 缓存的内容将在 xxx 秒后失效,这个选项只在 HTTP1.1 可用,并如果和 Last-Modified 一起使用时,优先级较高。