欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  web前端

跟我学习javascript的异步脚本加载_javascript技巧

程序员文章站 2022-04-06 23:16:16
...
先来看这行代码:

这有点儿……不怎么样。“这该放在哪儿?”开发人员会奇怪,“靠上点,放到

标签里?还是靠下点,放到标签里?”这两种做法都会让富脚本站点的下场很凄惨。标签里的大脚本会滞压所有页面渲染工作,使得用户在脚本加载完毕之前一直处于“白屏死机”状态。而标签末尾的大脚本只会让用户看到毫无生命力的静态页面,原本应该进行客户端渲染的地方却散布着不起作用 的控件和空空如也的方框。

完美解决这个问题需要对脚本分而治之:那些负责让页面更好看、更好用的脚本应该立即加载,而那些可以待会儿再加载的脚本稍后再加载。但是怎样才能既滞压这些脚本,又能保证它们在被调用时的可用性呢?

一、

现代浏览器中的

1、阻塞型脚本何去何从?

标准版本的

基于上述原因,现在越来越流行把脚本放在页面

标签的尾部。这样,一方面用户可以更快地看到页面,另一方面脚本也可以主动亲密接触DOM 而无需等待事件来触发自己。对大多数脚本而言,这次“搬家”是个巨大的进步。

但并非所有脚本都一样。在向下搬动脚本之前,请先问自己2 个问题。

  • 该脚本是否有可能被标签里的内联JavaScript 直接调用?答案可能一目了然,但仍值得核查一遍。
  • 该脚本是否会影响已渲染页面的外观?Typekit 宿主字体就是一个例子。如果把Typekit 脚本放在文档末尾,那么页面文本就会渲染两次,即读取文档时即刻渲染,脚本运行时再次渲染。

上述问题只要有一个答案是肯定的,那么该脚本就应该放在

标签中,否则就可以放在标签中,文档形如:

这确实大大缩短了加载时间,但要注意一点,这可能让用户有机会在加载bodyScripts.js 之前与页面交互。

2、 脚本的提前加载与延迟运行

上面建议将大多数脚本放在

中,因为这样既能让用户更快地看到网页,又能避免操控DOM之前绑定“就绪”事件的开销。但这种方式也有一个缺点,即浏览器在加载完整个文档之前无法加载这些脚本,这对那些通过慢速连接传送的大型文档来说会是一大瓶颈。

理想情况下,脚本的加载应该与文档的加载同时进行,并且不影响DOM 的渲染。这样,一旦文档就绪就可以运行脚本,因为已经按照

如果大家已经读到这里了,那么一定会迫不及待地想写一个自定义Ajax 脚本加载器以满足这样的需求!不过,大多数浏览器都支持一个更为简单的解决方案。


添加defer(延迟)属性相当于对浏览器说:“请马上开始加载这个脚本吧,但是,请等到文档就绪且所有此前具有defer 属性的脚本都结束运行之后再运行它。”在文档

标签里放入延迟脚本,既能带来脚本置于标签时的全部好处,又能让大文档的加载速度大幅提升!

不足之处就是,并非所有浏览器都支持defer属性。这意味着,如果想确保自己的延迟脚本能在文档加载后运行,就必须将所有延迟脚本的代码都封装在诸如jQuery 之$(document).ready 之类的结构中。

上一节的页面例子改进如下:


请记住deferredScripts 的封装很重要,这样即使浏览器不支持defer,deferredScripts 也会在文档就绪事件之后才运行。如果页面主体内容远远超过几千字节,那么付出这点代价是完全值得的。

3、 脚本的并行加载

如果你是斤斤计较到毫秒级页面加载时间的完美主义者,那么defer也许就像是淡而无味的薄盐酱油。你可不想一直等到此前所有的defer 脚本都运行结束,当然也肯定不想等到文档就绪之后才运行这些脚本,你就是想尽快加载并且尽快运行这些脚本。这也正是现代浏览器提供了async(异步)属性的原因。


如果说defer 让我们想到一种静静等待文档加载的有序排队场景,那么async 就会让我们想到混乱的无*状态。前面给出的那两个脚本会以任意次序运行,而且只要JavaScript 引擎可用就会立即运行,而不论文档就绪与否。
对大多数脚本来说,async 是一块难以下咽的鸡肋。async 不像defer那样得到广泛的支持。同时,由于异步脚本会在任意时刻运行,它实在太容易引起海森堡蚁虫之灾了(脚本刚好结束加载时就会蚁虫四起)。
当我们加载一些第三方脚本,而且也不在乎它们谁先运行谁后运行。因此,对这些第三方脚本使用async 属性,相当于一分钱没花就提升了它们的运行速度。
上一个页面示例再添加两个独立的第三方小部件,得到的结果如下:


这个页面结构清晰展示了脚本的优先次序。对于绝大多数浏览器,DOM的渲染只会延迟至headScripts.js 结束运行时。进行DOM渲染的同时会在后台加载deferredScripts.js。接着,在DOM 渲染结束时将运行deferredScripts.js 和那两个小部件脚本。这两个小部件脚本在那些支持async 的浏览器中会做无序运行。如果不确定这是否妥当,请勿使用async!
二、可编程的脚本加载
虽然