defer、async属性以及JS异步加载并执行解决方案

本文探讨了defer和async属性在JavaScript中的执行顺序,指出内联脚本在不同浏览器中的行为差异,并强调了外部脚本和defer的使用优势。同时,作者提供了关于如何合理使用这些属性,以及避免阻塞页面渲染的建议,包括利用DOMContentLoaded和AJAX加载JS等内容。
摘要由CSDN通过智能技术生成

defer测试代码,可将代码复制到本地自己测试,外部脚本src引入,内联脚本直接粘帖

运行以上代码,得出以下结论:

  • 外部JS在各个浏览器里运行结果跟定义的执行顺序正常,alert信息会按照 script->defer->onload顺序弹出;

  • 内联脚本,如果脚本都是IE9/8/7/6按照定义的顺序弹出信息,其他浏览器则按照 defer->script->onload 顺序弹出信息,表示defer失效。

  • 而如果有多个内联defer脚本、在body和head都有分布或者在iframe中也有内联defer脚本,则在IE6中表现一致。

如果想给脚本增加defer属性让其延迟加载的话,最好是外部脚本,内联的defer不仅多数浏览器不支持,而且IE6的表现也不一致。

所以将脚本放在body底部比给脚本增加defer属性让脚本延迟加载更好,就像yslow建议的那样:put style top,put script bottom。

浏览器的在遇到defer和async属性的

  1. WEB浏览器创建Document对象,并且开始解析WEB页面,解析HTML元素和它们的文本内容后添加Element对象和Text节点到文档中。这个过程的readystate的属性值是“loading”

  2. 当HTML解析器遇到没有async和defer属性的

JS异步加载


了解浏览器在遇到async、defer属性的脚本执行顺序,我们可以利用这两个属性来改善JS的阻塞问题,使用这两个属性会有几种可能的情况:

  • defer为true:延迟加载脚本,在文档完成解析完成开始执行,并且在DOMContentLoaded事件之前执行完成。

  • async为true:异步加载脚本,下载完毕后再执行,在window的load事件之前执行完成

利用这两个属性异步加载js,还得了解它们的毛病:

  • 使用defer属性,最好是外部的script

  • 使用defer、async的脚本禁止使用document.write()方法

  • 当脚本尝试访问的样式属性可能尚未加载的样式表时,浏览器会禁止该脚本等待样式表加载完成,这等于样式表阻塞了脚本的执行。所以使用defer、async的脚本最好不要请求样式信息时。

不管是使用defer还是async属性,都需要首先将页面中的js文件进行整理,各个脚本文件之间的依赖性,哪些文件可以延迟加载等等,做好js代码的合并和拆分,然后再根据页面需要合理的使用这两个属性。defer属性声明这个脚本中将不会有 document.write 或 dom 修改。

当所有脚本解析完成后,JavaScript进入第二个阶段,这个阶段的是异步的,并且由事件驱动的。在事件驱动阶段,WEB浏览器调用事件处理程序函数,来响应异步发生的事件。调用事件处理函数通常是用户输入,网络活动,运行和JavaScript中的错误来触发。

通过注册事件处理程序函数来处理程序,注册的事件在发生时异步调用这些函数,setTimeout()和setInterval()也都是异步的。所以页面内容中有内联script放在setTimeout()执行是异步JS的一种方法,当然将代码程序放在DOMReady内执行也是异步加载的方法。两者都将代码执行阶段放在了事件驱动阶段。

在dom中创建的script标签在浏览器中则是异步,如下:

function delay_js(src){

var objScript = document.createElement(‘script’);

objScript.setAttribute(‘src’, src);

objScript.setAttribute(‘type’, ‘text/javascript’);

document.body.appendChild(objScript);

return objScript;

}

异步加载JS

以上代码异步加载的JS下载是跟其他一样是并行的,但是执行阶段还是会阻止页面渲染,延长了window.onload的事件。怎么样才能下载和执行JS都不阻塞页面的渲染呢,如下:

function loadjs(src, succ) {

var elem = delay_js(src);

if ((navigator.userAgent.indexOf(‘MSIE’) == -1) ? false: true) {

elem.onreadystatechange = function() {

if (/loaded|complete/.test(this.readyState)){

succ()

}

};

}else{

elem.onload = function(){

succ();

}

}

elem.onerror = function() {};

}

JS异步下载+执行方案

代码分析:

  • 非IE浏览器能捕捉到script的onload事件,而IE捕捉不到 script.onload 事件,所以只能借助script.onreadystatechange.

  • 检测onreadystatechange状态中,IE7/8最后一个状态就只是loaded,而IE6中最后一个状态可能 complete 也可能是loaded,所以用正则loaded|complete两个状态都检测。

异步加载JS的问题是无法使用 document.write 输出文档内容,因为根本无法确定 document.write 应该输出到什么位置,但还是可以在DOMReady之后执行操作dom

异步加载的其他方法

除了DOMContentLoaded 与 OnLoad 事件、async属性以及defer属性script能解决JS异步加载外,还有其他方法可以异步加载JS:

  • 通过ajax获取js内容,然后eval执行。

var xhrObj = getXHRObject();

xhrObj.onreadystatechange =

function() {

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)

最后

今天的文章可谓是积蓄了我这几年来的应聘和面试经历总结出来的经验,干货满满呀!如果你能够一直坚持看到这儿,那么首先我还是十分佩服你的毅力的。不过光是看完而不去付出行动,或者直接进入你的收藏夹里吃灰,那么我写这篇文章就没多大意义了。所以看完之后,还是多多行动起来吧!

可以非常负责地说,如果你能够坚持把我上面列举的内容都一个不拉地看完并且全部消化为自己的知识的话,那么你就至少已经达到了中级开发工程师以上的水平,进入大厂技术这块是基本没有什么问题的了。

积蓄了我这几年来的应聘和面试经历总结出来的经验,干货满满呀!如果你能够一直坚持看到这儿,那么首先我还是十分佩服你的毅力的。不过光是看完而不去付出行动,或者直接进入你的收藏夹里吃灰,那么我写这篇文章就没多大意义了。所以看完之后,还是多多行动起来吧!

可以非常负责地说,如果你能够坚持把我上面列举的内容都一个不拉地看完并且全部消化为自己的知识的话,那么你就至少已经达到了中级开发工程师以上的水平,进入大厂技术这块是基本没有什么问题的了。

资料领取方式:戳这里前往获取

  • 22
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值