很久以前,我看了汤姆·克鲁斯、布拉德·皮特和克尔斯滕·邓斯特主演的电影“夜访吸血鬼”。给我印象最深的一个场景是,皮特饰演的角色意识到莱斯特正在利用他来适应当今时代。对于开发者来说,这不是一个坏规则。事实上,它非常好。如果你想跟上潮流并保持领先地位,跟随前沿技术,进行实验并复制他人的做法。逆向工程和重新发明轮子是一种幸福。将其应用于开源,我们——开发者、黑客、设计师——手中拥有大量工具。只需想想 Web 浏览器中的“查看源代码”。没有它,我们不可能达到今天的水平。复制就是学习。没有站在前人的肩膀上,发明是不可能的。
我工作的公司,Tail-f Systems 最近刚刚开源了一个名为 JAL 的小型 JavaScript 库,它是“Just Another Loader”的首字母缩写。这是一个初生的项目,缺少某些功能,但可以胜任工作并且做得很好。顾名思义,它是一个用于并行条件依赖加载资源文件的工具。我们在我们的 Web UI 中使用它来加载脚本和 CSS 文件。它存在的唯一原因是:为了加快速度!
我们测试了 YepNope,这是一个很棒的加载器,但感觉它可以更快。它还有一些我们并不需要的功能。所以我们自己编写了一个。我们重新发明了轮子。这能有多难?好吧,这相当困难。
我们需要一个资源加载器,它不仅可以加载 JavaScript,还可以加载样式表。它还需要能够并行加载和分组加载资源以处理依赖关系,例如在加载 jQuery 插件之前加载 jQuery。最后一个要求是条件加载,即如果浏览器缺少原生 JSON 支持,则加载 JSON.js。
并行依赖加载
典型的设置如下所示
$loader
.load('js/shape.js')
.load([
'js/circle.js'
, 'js/rectangle.js'
])
.load('js/square.js')
.ready(function() {
// Start app
})
设置了三个依赖组。第一个加载一个形状。第二个加载一个圆形和一个矩形,它们依赖于形状。最后一组包含一个正方形,它派生自一个矩形。在这个简单的例子中,速度提升发生在第二个组,因为圆形和矩形是并行加载的。现在,想象一下,您的应用程序中有大量具有不同依赖关系的脚本。传统的方法是将所有脚本连接到一个大型捆绑包中,然后压缩该捆绑包。您实际上是在以旧的方式加载脚本,一个接一个地加载。现代浏览器能够并行加载脚本和资源。它们实际上会打开到 Web 服务器的多个连接,并同时加载多个资源。因此,如果您有一个脚本需要 5 秒才能加载,并且您将其分成 5 部分并并行加载这些部分,那么加载时间理论上将变为 1 秒。这比之前快了五倍!
条件加载
现在来看条件加载。条件加载是在满足特定条件时加载资源。浏览器是否具有原生 JSON 支持?没有?好吧,我们会解决这个问题!这是一个加载 JSON polyfill 的示例
$loader
.when(typeof window.JSON === 'undefined', function(loader) {
loader.load('js/json.js')
})
已完成
一旦资源组加载完毕,JAL 允许您执行代码。这是一个示例,其中 jQuery 中的“ready”事件在所有脚本加载完毕之前都会暂停。
$loader
.load('js/jquery.min.js')
.done(function(){
// Stop jQuery from triggering the "ready" event
$.holdReady(true)
})
.load([
'js/script-one.min.js'
, 'js/script-two.min.js'
])
.ready(function() {
// Allow jQuery to trigger the "ready" event
$.holdReady(false)
// Start app
})
它是如何完成的
编写 JAL 既具有挑战性又很有趣。最困难的部分是确保组之间保持加载顺序。这很棘手,因为事情发生得很快,并且浏览器之间的性能差异很大。
JAL 使用资源队列和轮询函数实现。在资源组加载完毕之前,队列处于锁定状态。加载完成后,会触发“done”事件。如果您需要,这允许您将一个或多个资源组注入到队列的前面。触发“done”事件后,队列将解锁,并且轮询器可以自由加载下一个资源组。
一旦加载器序列执行完毕,轮询器本身就会启动。这是通过使用超时时间为 0 毫秒的 setTimeout
将轮询器推送到脚本堆栈顶部来完成的。这是 Web 浏览器 JavaScript 引擎单线程模型如何使用的经典示例。
结语
您是否有一个大型连接的 JavaScript 文件?它是否已压缩并进行了 gzip 压缩?它加载速度快吗?您想要更快吗?然后分别压缩并进行 gzip 压缩您的资源文件,并改用条件并行依赖加载器。
关于 Helgi Kristjansson
Helgi Kristjansson 是一位来自冰岛的 JavaScript 维京人。他于 1998 年入侵瑞典,在那里他主要从事与硬件相关的行业中基于 Web 的用户界面的开发工作。他目前的雇主是 Tail-f Systems,一家位于斯德哥尔摩的公司。您可以在 Twitter 上通过 @djupudga 联系 Helgi。
7 条评论