Html5-boilerplate: 脚本加载解决方案

创建于 2010-08-10  ·  132评论  ·  资料来源: h5bp/html5-boilerplate




此问题线程现已关闭。

这很有趣,但现在谈话已经转移到其他地方。 谢谢

为了感谢我们度过的欢乐时光, @rmurphey为我们制作了一个快乐的线程词云。

享受。





通过 labjs 或 require。

我的“样板”load.js 文件内嵌了 LABjs,然后使用它来加载 jquery、GA 和一个站点 js 文件。 如果有帮助,我在一个文件中集成了 RequireJS+jQuery:http://bit.ly/dAiqEG ;)

这也如何满足连接和缩小所有脚本的构建脚本的期望? 脚本加载应该是一种选择吗?

javascript

所有132条评论

凯尔:“@paul_irish我不同意。 http://bit.ly/9IfMMN可缓存(外部CDN的),并行下载,脚本变化波动......”

james burke:“ @paul_irish @fearphage @getify RequireJS 有构建工具来进行脚本捆绑/缩小,所以可以兼得:动态和预构建”

开发人员开始脚本加载的最简单方法可能是使用 $Lab.js,因为它已经使用了 jQuery 用户熟悉的链式语法。

如果他们正在构建大型企业应用程序,他们总是可以在需要时迁移到 require.js。

目前有三种主要的脚本加载技术:

  1. HeadJS
  2. 控件JS
  3. 实验室

使用与否,使用哪个有点值得商榷: http :

还有requireJSEnhanceJS只是为了让你知道HeadJS ControlJSLabJS的替代品。 甚至雅虎和谷歌也提供类似的服务。

随着 jQuery 1.5 和 deferreds -- http://www.erichynds.com/jquery/using-deferreds-in-jquery/ 的发布,Boris Moore 在 DeferJS 中使用它们,一个新的脚本加载器项目: https://github。 com/鲍里斯摩尔/DeferJS

默认情况下,脚本加载会停止所有其他下载,因此在标题中下载 Modernizr 是不好的。 内联加载器是有意义的,因为加载器可以在非阻塞模式下并行下载脚本。 例如,如果您不需要所有 Modernizr 功能,您可以内联只有 6kb 的 head.min.js 或 Modernizr (http://modernizr.github.com/Modernizr/2.0-beta/) 的自定义构建。 内联 CSS 有时也有意义。 Google 使用内联,他们通过 datauri 内联 css、js 和空的 1x1 gif。

LabJS 正在被广泛使用并且是一个很好的解决方案 - 它也可以异步包含,因此不需要阻塞。

http://blog.getify.com/2010/12/on-script-loaders/作者

http://yepnopejs.com/刚刚更新到 1.0 并且不会在新的 webkit 中崩溃,这与 LAB 和 head.js 不同。 脚本加载很困难。

yepnope 也作为Modernizr.load集成到 Modernizr 中.. http://modernizr.github.com/Modernizr/2.0-beta/

所以我们可能很快就会通过 Modernizr.load 在 h5bp 中拥有一个脚本加载器。

我不认为它会成为 1.0,但是一旦我将 Modernizr 提高到 1.8,我们就会将它扔到 h5bp 1.1 中。 呀呀

嗨保罗

我已经移植了一个现有站点以使用您的 H5BP,并且我想使用 yepnope.js 脚本加载器。 很高兴看到所有的点点滴滴和机器人都像你所做的那样组合在一起。

您目前建议使用什么?

  1. 在页面顶部包含 yepnope.js 和 Modernizer.js
  2. 将它包含在页面底部,在 HTML 加载完成后加载。
  3. 使用 Modernizer.js 的测试版
  4. 我可以将 yepnope.js 与 Modernizer.js 连接成一个包含。

无论如何最好地包含它,您建议如何使用 yepnope,js 加载脚本?

我想我们应该在这里做: https :

但是,您认为最好使用外部脚本在 html 中包含或呈现脚本块,然后通过 yepnope.js 加载脚本吗?

非常感谢。

安迪

哦还有另一件事。

由于 yepnope 可以通过加载 css,我会说最好像往常一样包含主 css,并使用 yepnope 仅包含用于特定修复的 css。

例如,包括一些仅适用于旧版本 IE 的 css。

霍卡波卡,

使用 Modernizr 的 beta 版本.. 只需包含您需要的内容(并包含Modernizr.load() ),然后将其放在页面顶部。

带有 yepnope 的 jquery 回退的实际代码位于http://yepnopejs.com/

是的,我喜欢你对 IE css 的条件加载的想法。

tbh 对脚本加载器的性能有太多的盲目信仰,我认为我们还没有准备好说这是正确的方法。

我们需要对文件大小、带宽和网络条件进行更多研究,以表明对脚本加载的智能建议,但现在该领域尚处于起步阶段,我们还天真地推荐脚本加载的全面解决方案。

所以。

关闭这张票并询问任何关心进行全面研究和发布所需的人,以使开发人员更容易对此做出明智的选择

我对 concat 与并行负载做了很多研究。 我仍然毫无保留地建议先将所有 js 合并到一个文件中,然后将其分成 2-3 个相同大小的块,然后并行加载它们。

我希望能够进行我的研究并使其广泛传播和扩展,以便它在该领域成为可行的“事实”。 问题是我已经尝试并试图找到托管带宽,在这种情况下,实际大规模运行测试不会花费我很多美元,但还没有找到托管服务。

如果我/我们可以解决测试的带宽问题,我就有可以运行的测试来确定并行加载的理论是否真的可行(正如我所相信的)。

@getify就测试设备而言,您需要什么?

我可以从我的个人服务器中处理比我目前使用的数据多 1.5TB 的数据。 我安装了 Nginx,每微秒可以处理大约 4 万亿次点击。 我不觉得技术是这里的障碍。

如果我们担心位置,我们可以欺骗更高的延迟,和/或找到其他几个在他们的盒子上有一点额外空间的人。

顺便说一句,我对“盲目信仰”有点异议。

很容易、可以证明,而且几乎毫无疑问,如果您有一个现有站点加载许多带有脚本标签的脚本,使用并行脚本加载器(没有其他更改)可以提高性能。 这是真的,因为即使是最新的浏览器也不能(也永远不会,我不认为)从阻止 DOM-ready 中取消固定脚本加载。 因此,即使在最佳情况下浏览器加载,如果没有其他好处,大幅加快站点上的 DOM 就绪几乎总是一个胜利(对于用户和 UX)。

您的陈述有点错误的前提,因为它假设我们正在尝试将每个站点的并行加载与脚本连接进行比较。 网络上的大多数网站实际上都没有/不能使用 script-concat,所以实际上比较(对他们来说,大多数)并不像你想象的那么细致和复杂。 如果他们不/不能使用 script-concat(无论出于何种原因),比较很简单:并行加载几乎总是胜过脚本标签。

如果他们对 script-concat 开放(或已经使用它),那么是的,它确实会变得更加微妙/复杂,以确定并行加载是否有帮助。 但是 script-concat 也不是一刀切的灵丹妙药,所以有很多站点并行加载仍然是首选和最好的方法。

仅仅因为某些站点处理在并行加载与脚本连接之间做出决定的细微差别/复杂性并不意味着应该在混合中丢失对并行加载与脚本标记的更大(更有影响力)的讨论。 前者很难证明,但后者在这一点上几乎是既定的。


这就是说,考虑到所有因素,恕我直言,样板应该鼓励一种在积极方向上具有最大影响的模式。 如果当今互联网上 80% 的站点都使用脚本标签,其中大部分会受益于从脚本标签移动到并行加载,那么并行加载是一个非常健康的建议,作为样板的起点。

它是那些站点的一个小得多(但重要)的子部分,可以从探索脚本连接与并行加载中获得更多好处。 但是少数用例不是应该在样板中优化的。

只是我的几美分。

@paulirish @slexaxton --

就带宽需求而言,我估计要让 10,000 人(我认为需要进行准确采样)运行一次测试(我敢肯定,很多人会运行几次),大约需要花费了 200GB 的带宽。 对于某些人来说,这只是杯水车薪。 对我来说,几天之内 200GB 的带宽对于我的服务器托管成本来说是压倒性的。 所以,我并没有仅仅因为这个原因而追求扩展测试。

此外,我认为我们需要探索这个测试的十几种变体。 因此,数十次使用 100-200GB 的带宽对于我来说是非常昂贵的。 除非我确定我有足够的带宽来完成任务,否则我不想开始那条路。

它们只是静态文件,测试不需要大量并发用户,因此没有真正担心 CPU 等传统扩展问题。只是带宽,仅此而已。

我们可以将测试的其余讨论脱机并通过电子邮件或 IM 进行。 我非常想最终扩展测试并“解决”这个问题。 它已经在我的大脑后面徘徊了一年的大部分时间。

我可以在我的 Dreamhost VPS 上做无限的 TB,所以这不会成为问题。 现在我每天做 72GB 并且可以处理更多。 :)

我同意 paul 的观点,并且认为关于脚本加载器如何以及何时对任何人有益的错误信息很多。

你的第一段说脚本加载器提高性能是“容易”、“可证明”和“毫无疑问”的。

不久前,我对

https://github.com/SlexAxton/AssetRace

代码就在那里。 显然没有大量的测试受众,但结果充其量表明这个脚本加载器与 concat 方法的速度大致相同(遵循类似大小的 3 文件并行加载指南),最坏的结果表明脚本-装载机变化更大,通常在误差范围内变慢。 随意 fork 并找到比我们更好的解决方案,即使它只是在您的机器上的一个浏览器中。

至于“错误前提”,因为 h5bp 假设人们连接他们的 js。 这个论点是完全无效的,因为 h5bp 提供了一个脚本构建工具,完成了 concat 和 minification。 因此,并行加载几乎总是战胜多个脚本标签的论点可能是正确的,但它并不比 h5bp 当前提供的更好。 这就是本次讨论的背景。

我认为最糟糕的情况是人们使用 yepnope 或 lab.js 之类的东西并将其用作脚本标签 polyfill。 这绝对会导致加载速度变慢(他们的 19 个 JS 和 34 个 CSS 文件),并引入了一系列他们完全不知道的向后和向前兼容性问题。

我认为本着为 _boilerplate_ 为人们提供最明智、最高效和最兼容的默认值的精神,构建工具更进一步以确保所有三个。

@slexaxton

...结果充其量表明此脚本加载器与 concat 方法的速度大致相同(遵循类似大小的 3 文件并行加载指南)...

我会很高兴地找一些时间来看看你放在一起的测试。 我相信你们知道自己在做什么,所以我相信你们的测试是有效和正确的。

OTOH,我有很多相互矛盾的证据。 如果我曾经看到任何令人信服的内容表明并行脚本加载对大多数站点来说是一种浪费或无益,我早就放弃了 LABjs 的疯狂时间槽。

我可以 100% 肯定地说,在帮助人们将 LABjs 推出的 2 年里,我从未发现 LABjs 比脚本标签替代品慢的情况。 对我来说,这种情况发生过零次。 有几次人们说他们没有看到太多好处。 有几次人们加载了 100 多个文件,因此大量连接的疯狂开销抹去了他们本来可以看到的任何好处。 但我从未有人告诉我 LABjs 使他们的网站变慢了。

我自己确实帮助 50 多个不同的站点从脚本标签迁移到了 LABjs,并且毫无疑问,站点立即看到了性能改进。 在早期的努力中,我对我帮助过的大约 7 或 8 个站点进行了抽样,他们共同发现加载速度平均提高了 15%。 对于我管理的 4 或 5 个站点,我当然实施了 LABjs,并立即看到了高达 3 倍的加载速度。

当然,当 LABjs 首次出现时,浏览器并行加载脚本是最先进的(只有少数人这样做)。 因此,当时的收益是巨大且可见的。 现在,我们几乎所有浏览器都在进行并行加载,因此收益不再那么大了。

但不可否认的一件事是浏览器都阻止了用于加载脚本标签的 DOM-ready 事件。 他们_不得不_因为有可能找到document.write() 。 并行脚本加载本质上是在说“浏览器,我保证你不必处理 document.write,所以继续前进”。

看看这张牌的幻灯片 10 上的两个图表:

http://www.slideshare.net/shadedecho/the-once-and-future-script-loader-v2

比较蓝线的位置(DOM 就绪)。 即使整体页面加载时间(或完成所有资产加载的时间)也没有任何改善,这也是感知性能 (UX) 的显着改进。

...h5bp 提供了一个脚本构建工具...

这里错误的假设是,仅仅因为 h5bp 提供了这个工具,h5bp 的所有(甚至大多数)用户都可以使用它。 即使 100% 的 h5bp _do_ 用户使用它,这并不意味着如果将 h5bp 推出到互联网的长尾,他们都会使用该 concat 工具。 还有很多其他因素可以很容易地阻止某人使用它。 有_非常少_的原因为什么有人不能从使用脚本标签转向使用并行脚本加载器。

因此,并行脚本加载仍然为互联网的长尾提供了更广泛的吸引力。 对于大多数不使用脚本加载优化的站点来说,从无到有移动仍然更容易,并且某些东西为他们提供了性能优势。 这些长尾站点中很少有人会在其每月 6 美元的廉价、大规模共享托管、非 CDN 的网络托管环境中花费精力(或有能力尝试)自动化脚本构建工具。

我认为最糟糕的情况是人们使用 yepnope 或 lab.js 之类的东西并将其用作脚本标签 polyfill。 这绝对会导致加载速度变慢......

我不能更不同意这个说法。 LABjs 专门设计为脚本标签 polyfill。 并且 LABjs 对常规脚本标签的改进(暂时忽略脚本 concat)已经确立并且从未被严重反驳。 如果您有证据表明大多数(甚至很多)使用 LABjs 的站点最好返回脚本标签,请分享。

完全没有理由为什么并行脚本加载会导致加载速度比浏览器使用脚本标签所能完成的加载速度慢。 这是没有意义的。 正如我在上面建立的,脚本标签将始终阻止 DOM-ready,而并行脚本加载不会。

引入了一系列他们完全不知道的向后和向前兼容性问题。

你在谈论什么兼容性问题? LABjs 的浏览器支持矩阵绝对涵盖了地球上所有网络浏览器的绝大多数。 它闯入的疯狂的一小部分浏览器远远超过它具有明显优势的大量浏览器。

LABjs 1.x 中有一堆疯狂的 hack,比如缓存预加载,这确实是浏览器损坏的主要问题。 LABjs 2.x 完全颠倒了这一点,现在在所有情况下都使用可靠和标准化的方法进行并行加载,只是退回到旧 webkit 浏览器的 hack。 此外,LABjs 2.x 已经检查了即将推出的脚本加载技术(希望很快标准化)的功能测试,例如“真正的预加载”。

我不能肯定地谈论任何其他脚本加载器——我知道很多人仍然在使用 hacks——但是对于 LABjs,我对它引入向前或向后兼容性问题的说法感到困惑,因为我认为这显然是一种误导宣称。

稍微详细说明为什么我打算让 LABjs 实际上是一个脚本标签 polyfill...

  1. 较旧的浏览器显然在处理并行加载可以处理的脚本标签加载方面表现不佳。 正是在那些“旧浏览器”(两年前 LABjs 推出时最新/最好的浏览器)中,我们看到了大约 3 倍的页面加载时间改进。 几乎根据定义,这使 LABjs 成为更好的脚本标签 polyfill,因为它为本身不支持它的浏览器带来了一个特性(即并行加载的性能)。
  2. 较新的浏览器显然要好得多。 但它们并没有完全消除脚本加载器的好处。 chrome 最近在 v12(我猜他们似乎终于在 v13 中修复了)在脚本标签完成加载时仍然阻止图像加载。 即使使用最新的 IE、Firefox 和 Chrome,它们仍然会在动态加载脚本时阻止 DOM-ready,因为它们仍然必须悲观地假设document.write()可能潜伏着。

因此,对于较新的浏览器,LABjs 是一种“polyfill”,因为它以脚本标签无法做到的方式将“非 DOM 就绪阻止脚本加载”引入浏览器。 在没有并行脚本加载器的现代浏览器中,唯一可能的方法是使用带有defer脚本标签( async显然不起作用,因为它不保留顺序) . 然而, defer有许多怪癖,它的支持还不够广泛,不足以成为一个可行的解决方案(非延迟的后备是性能不佳)。 所以你可以说,在最基本的情况下,LABjs 是脚本标签defer (虽然不完全是)的性能特征的一个 polyfill。

老实说,我仍然认为我们应该为脚本加载对象申请标准。 必须创建与 text/javascript 不同类型的脚本标签来触发缓存(或者更糟的是,使用对象标签或图像对象或流行浏览器的新版本需要的任何东西)是白费力气性能会因变量过多而有所不同。 我可以理解我们仍然使用 dom 节点插入加载样式表(但这只是因为顺序)但是当涉及到脚本时,我认为它不再有意义(我希望谷歌在大多数情况下停止使用 document.write他们的剧本,但这完全是另一个故事)。

此外,我认为我们在这里错过了关于脚本加载器的最重要的一点:能够按需加载 js 代码而不是预先加载所有内容(即使所有内容都在缓存中,解析和初始化需要时间,并且可以变得漂亮丑陋的大量串联脚本)。 在 UI 交互之后有一些等待时间比在启动时让浏览器“挂起”甚至一点点问题要少得多(DOM 可能已经准备好了,但是如果代码来增强页面有什么好处呢?并添加迭代尚未执行:有没有注意到某些站点如何立即加载然后发生一些笨重的事情?)。

如此严格的性能测量都很好,但我仍然认为感知性能是最终目标......遗憾的是,估计/优化/计算要容易得多。

这是激烈的。

@jaubourg--

老实说,我仍然认为我们应该为脚本加载对象申请标准。

关于标准/规范和浏览器如何为我们提供更好的脚本加载技术,有很多请愿活动。 多年来该类别中的第一个重大胜利是“有序异步”( async=false ),它在 2 月份被采用,现在在每个主要的当前发布的浏览器中(例外:Opera 即将推出,而 IE10p2 拥有它)。

下一场辩论,我目前正在与 Ian Hickson 讨论,我称之为“真正的预加载”。 在我看来,“真正的预加载”(IE 已经从 v4 开始支持,顺便说一句)将是最接近“银弹”的东西,它可以相当简单地解决几乎所有脚本加载场景。 我仍然很乐观,我们会看到这样的标准化。

有关更多信息,请参阅此 wiki: http :

必须创建与 text/javascript 不同类型的脚本标签来触发缓存(或者更糟的是,使用对象标签或图像对象或流行浏览器的新版本需要的任何内容)

这称为“缓存预加载”,这是公认的丑陋和可怕的黑客攻击。 从 v2 开始,LABjs 的方式现在不再强调这一点(仅将其用作旧 webkit 的后备)。 不幸的是,其他脚本加载器仍然使用它作为他们的主要加载机制。 但是 90% 的“缓存预加载”需求可以通过“有序异步”解决,这是标准化的,不是黑客,所以行为良好的脚本加载器现在应该更喜欢“缓存预加载”。

所以,我同意“缓存预加载”很糟糕,但有更好的方法来使用document.createElement("script")而不涉及此类黑客,所以我不同意这是反对继续依赖浏览器脚本元素的论点脚本加载。 如果我们能够获得“真正的预加载”,那么 Script 元素将是我们需要的一切。 老实说,我相信这一点。

我认为我们在这里错过了关于脚本加载器的最重要的一点:能够按需加载 js 代码

非常同意这是脚本加载器带来的重要好处。 但这在 _this_ 线程中有点没有实际意义,因为“脚本连接”人员在没有脚本加载的情况下根本无法解决用例,因此“比较”两者毫无意义。 作为“脚本连接”的支持者,您可以说“很好,我们不关心那个用例”,但您不能说“我们可以使用 XYZ 更好地为该用例提供服务”。

感知性能_is_巨大而重要,我同意。 按需加载是实现这一目标的重要组成部分。 按需加载还将提高实际的实际性能(不仅仅是感知),因为如果您只下载需要的内容(很少有页面访问需要 100% 的代码),它往往会导致实际下载的更少。

感知性能也是我提倡上述 DOM-ready 论点的原因。 因为用户“感觉”他们可以与页面交互的速度对他们认为页面的速度非常重要(无论它真正加载的速度有多快)。 这是由大量用户研究确定的事实。

一定要喜欢@getify 充满激情的长评论
凯尔...

如果我能以任何方式为研究做出贡献,我会_爱_。
带宽(成本)似乎不是问题,所以@getify ,您对前进的建议是什么?
不要犹豫,通过电子邮件与我联系(aaron [at] aaronpeters [dot] 或 twitter (@aaronpeters)

@凯尔

是的,我遵循了关于预加载的脚本标签“增强”讨论,我只是不购买“在脚本标签上添加另一个属性”方法作为可行的方法。 我已经看到它对 xhr 规范做了什么:关于我们最终获得的小好处的很多复杂性。

很清楚的是,我们在进行动态插入时几乎只需要预加载行为(即已经在 javascript 中这样做了),那么为什么我们仍然应该使用脚本标记注入? 这不像我们将标签保留在那里或将其用作 DOM 节点:它只是达到目的的一种手段,与文档结构无关。

我会更喜欢这些方面的东西:

window.loadScript( url, function( scriptObject ) {
    if ( !scriptObject.error ) {
        scriptObject.run();
    }
});

这会产生奇迹。 很容易“加入”多个脚本加载事件,然后以任何必要的顺序运行这些脚本。 它也不意味着 DOM 的存在,这使得它更加通用。 我希望我们能尽快完全摆脱脚本标签注入。 此外,使用我们都知道的技巧来填充它很容易。 与完整的 require 系统相比,它的负担也小得多(但可以作为一个不限于浏览器的 require 系统的构建块)。

话虽如此,我 100% 同意你对感知性能的看法,我只是想指出这一点,因为“让我们把它全部压缩在一起”的口头禅正迅速成为某种信念,使我的口味变得过于模糊;)

fwiw, defer支持 IE4+、Chrome、Safari 和 FF 3.5+。 Opera 不支持。

所以这意味着...... 98.5% 的用户已经拥有script@defer支持。

@getify

然而, defer有许多怪癖,

lz详细吗? 我什么都没看到

带有延迟的脚本是在 DOM 就绪事件触发之前还是之后执行?

执行顺序是否保留在所有浏览器中?

执行顺序和外部与内联脚本的耦合如何?

@paulirish--

... 98.5% 的用户已经拥有script@defer支持。

可能有那么多浏览器支持,但这并不意味着它在那么多浏览器中是可靠的。 我正是这个意思。 (见下文)

然而, defer 有一些怪癖,

lz详细吗? 我什么都没看到

让我看看... IIRC:

  1. 任何浏览器都没有定义或支持对动态脚本元素的延迟支持......仅适用于标记中的脚本标签。 这意味着它对于“按需”或“延迟加载”技术和用例完全没用。
  2. 我相信有一种情况,在某些浏览器中,延迟脚本会在 DOM-ready 触发之前立即开始执行,而在其他浏览器中,它会在 DOM-ready 触发后立即执行。 需要做更多的挖掘以了解更多细节。
  3. 在引用外部资源的脚本标签上使用的defer与在其中包含内联代码的脚本标签上指定的defer行为不同。 也就是说,不能保证推迟两种类型的脚本并让它们仍然以正确的顺序运行。
  4. defer由一个写出来的脚本标签document.write()从脚本标记不同的标记与声明defer

关于这些问题,我手头上没有准备好大量细节。 我记得大约 2 年前(在 LABjs 之前)尝试使用defer ,并且在跨浏览器测试中遇到了足够多的它们,我基本上将其搁置一旁,此后并没有真正重新访问它。


我还应该指出, defer与 LABjs(和其他并行加载器)提供的并不是一回事。 我在上面说过,但要注意它只是有点像。 实际上,并行脚本加载提供的(至少对于 LABjs 的部分而言)是“有序异步”,这绝对无法仅通过标记来实现。

“有序异步”和“延迟”之间的区别在于,“有序异步”仍会在第一个请求的脚本加载完成后立即开始执行,而“延迟”将等到“DOM 就绪”才开始执行。 对于标记很少且没有其他阻塞标记调用(如其他脚本标记)的简单页面,这种差异很小。 但是对于具有大量资源的页面,允许脚本开始执行的时间可能会大不相同。

所以,老实说,我不想过多地关注defer的切线,因为实际上它与并行脚本加载提供的内容相比并不是一个很好的比较。 这只是标记中最接近的例子,我可以用它来描述我所得到的执行顺序行为。 我可能甚至不应该提出defer - 只是混淆了讨论。

让我从上面改写一下:“对于现代浏览器,LABjs 是一种用于‘有序异步’行为的‘polyfill’,在任何浏览器中都不可能选择仅标记。”

我喜欢“有序异步”,这是一个很好的短语。

Kyle > afaik,带有 defer 的脚本会在 _before_ onload 之前执行,甚至在 domready 之前。
具有 async 属性的脚本将尽快执行,并且_always_ _before_ onload,但不一定在 domready 之前

@aaronpeters--
我想你可能有点偏离轨道。 以下是我的理解:

async脚本(无论是在标记中还是动态创建的)将尽快执行,这意味着在 DOM 就绪之前或之后的任何时间。 换句话说, async脚本不应该等待任何东西(除了 JS 引擎本身的可用性)。 但是,如果在window.onload之前请求它们,那么在几乎所有浏览器中,它们都会“阻止” window.onload事件,直到它们加载和执行为止。 我认为有一个记录在案的案例,其中async脚本没有支持window.onload ,只是不记得确切的细节。

另一方面, defer的具体含义是:等到 DOM 就绪之后。 此外,所有设置了defer脚本都有一个“队列”,这样队列在 DOM 就绪之后才会被处理。这意味着它们都应该在 DOM 就绪之后(或者更确切地说,在DOM 已准备就绪并已完成解析,准确地说)。 但是它们可能会被进一步延迟(如果加载速度很慢)。 不过,他们应该坚持window.onload 。 我只是从模糊的过去记忆中回忆起,在某些版本的 IE 中,该理论的实际实践有点模糊。

@getify

不想再破坏这个线程,所以我在 WHATWG 页面上发布了我对脚本预加载的想法和您的建议: http :

async脚本(无论是在标记中还是动态创建的)将尽快执行,这意味着在 DOM 就绪之前或之后的任何时间。 换句话说, async脚本不应该等待任何东西(除了 JS 引擎本身的可用性)。 但是,如果在window.onload之前请求它们,那么在几乎所有浏览器中,它们都会“阻止” window.onload事件,直到它们加载和执行为止。

一旦您意识到 JavaScript 是单线程的,这可能更容易理解。 (我知道这花了我一段时间......)

同样,如果您使用setTimeout(fn, 0)下载资源,并且它们在onload触发之前进入下载队列,则加载这些资源将(仍然)延迟onload

我认为有一个记录在案的案例,其中async脚本没有支持window.onload ,只是不记得确切的细节。

我很想获得更多关于这方面的信息。 请记住! :)

是的脚本加载器!

我在 AOL 的网站网络中实施它们时遇到的一个问题是处理竞争条件。 例如,在头部异步加载 jQuery,然后在博客文章中异步交付的文档中间说一个 jQuery 插件。

因此,我开始了我自己的脚本加载器科学项目 (Boot.getJS) 来处理这个问题。 这个想法是并行下载所有脚本并尽快按顺序执行它们。 它还支持延迟就绪或加载,以及缓存脚本。 大多数想法都被这个线程上的人借用(窃取)了,所以谢谢大家。 :)

由于您正在讨论基准测试,我想我会分享一个我创建的测试页面,以了解各种脚本加载器在性能、语法和行为方面的差异,请在此处查看:

http://artzstudio.com/files/Boot/test/benchmarks/script.html

要查看各种加载器的行为方式,请清除缓存并查看网络请求和最终时间以及脚本执行的顺序。

Dave (@artzstudio),用于分享您的想法和测试页面链接的 txs。

问题:为什么要在 head 页面的“<script> 标签”上加载 LABjs? 这似乎是错误的。

@artzstudio同样,您使用的是旧版本的 LABjs。 这是故意的吗? 如果是这样,为什么?

@aaronpeters在 AOL,我们有像 Omniture 和广告代码(以及更多)这样的脚本,需要在头中输入,所以这就是我们用例中加载程序库所在的位置。 此外,当脚本位于底部时,我们的一些小部件中存在 FOUC 问题,因此加载依赖项(如 jQuery)越早越好。

这不是故意的,这个测试是几个月前的。 有机会我会更新库。

仅供参考(希望这有点有趣/相关),我在 Webpagetest.org 上进行了一些测试,以查看加载某些@artzstudio测试页面时 IE8 中会发生什么。
脚本标签: http :
是的: http :
LABjs: http :
RequireJS: http :

比较 Yepnope 和 LABjs 的视频: http :

一些注意事项:

  • Gzip 在服务器上是关闭的,所以 RequireJS 的较大文件大小的方式有影响
  • 如前所述,Script tags 页面在 HEAD 中加载 LABjs(没有意义),这当然有影响

由于这两个原因,我创建了一个仅显示 Yepnope 和 LABjs 的视频。

我觉得有趣的是,LABjs 的开始渲染时间要好得多。 这是为什么? 很想更好地理解。

结束语:我发布这篇文章的目的不是为了支持 LABjs 而不是 Yepnope 或类似的东西。 只是共享数据...

哦,抱歉,我明白您对 <script> 测试中的 LABjs 的意思。 现已修复,同时升级到 LABjs。

@artzstudio--

因此,我开始了我自己的脚本加载器科学项目 (Boot.getJS) 来处理这个问题。 这个想法是并行下载所有脚本并按顺序执行它们,无论如何,尽快

那么,您是否知道这正是 LABjs 的设计目的并且做得很好(如果我自己这么说的话)? 我的意思是,你只是想要一个不同的 API,或者并行脚本加载功能是不够的?


在任何情况下,尽管我喜欢吹嘘 LABjs,但我认为用“看,我的脚本加载器更擅长 X”类型的讨论来拖延这个线程是无效的。 这些讨论很有用,但在别处。

最后,所有脚本加载器技术都归结为几个简单的想法。 无论您在其上分层什么样的花哨 API,或者您迎合什么样的用例,技术都是一样的。 现在肯定有 50 种不同的脚本加载器,实际上,它们都没有提供任何不同的技术,只是不同的 API。 因此,比较 API 确实是一个无关紧要的讨论。

我们应该关注的是,与仅在标记中使用脚本标签相比,我们目前在浏览器中可用的基本脚本加载技术是否可以用于提高页面加载的性能。 这是我长期以来一直坚持的一个前提,它绝对正确,但这个前提在这个线程中受到了质疑。 所以任务#1 是回答这个问题。

如果我们发现脚本标签只是比脚本加载更好,那么我们可以停止所有这些疯狂并关闭我们所有的项目。 不过,我怀疑情况并非如此。 ;-)

任务#2 是一劳永逸地找出脚本连接是否总是比并行加载更好。 同样,我的前提(和我的测试)表明将所有文件合并为一个是好的,但是您必须将该大文件分成 2-3 个大致相等的部分并并行加载这些块。 因此,我们也确实需要测试该理论。

如果我们发现 script-concat 总是最好的,那么当您考虑到大多数站点从多个位置加载脚本(来自 Google CDN 的 jquery,来自谷歌的谷歌分析,facebook/twitter/g+ 按钮)时,脚本加载器仍然很有用, 等等)。 因此,作为任务 #3,我们需要确定 concat 是否更好,以至于您应该托管所有这些文件的自己的副本,并将它们与您自己的代码连接在一起。

Kyle,您能否查看我的示例的源代码并让我知道我将如何检测 LabJS 以按顺序(甚至在链外)执行页面上的所有脚本? 我很可能误读了 API(正如 Paul 所说,脚本加载器很难,%-)。

2011 年 8 月 10 日上午 9:09, [email protected]写道:

@artzstudio--

因此,我开始了我自己的脚本加载器科学项目 (Boot.getJS) 来处理这个问题。 这个想法是并行下载所有脚本并按顺序执行它们,无论如何,尽快

那么,您是否知道这正是 LABjs 的设计目的并且做得很好(如果我自己这么说的话)? 我的意思是,你只是想要一个不同的 API,或者并行脚本加载功能是不够的?


在任何情况下,尽管我喜欢吹嘘 LABjs,但我认为用“看,我的脚本加载器更擅长 X”类型的讨论来拖延这个线程是无效的。 这些讨论很有用,但在别处。

最后,所有脚本加载器技术都归结为几个简单的想法。 无论您在其上分层什么样的花哨 API,或者您迎合什么样的用例,技术都是一样的。 现在肯定有 50 种不同的脚本加载器,实际上,它们都没有提供任何不同的技术,只是不同的 API。 因此,比较 API 确实是一个无关紧要的讨论。

我们应该关注的是,与仅在标记中使用脚本标签相比,我们目前在浏览器中可用的基本脚本加载技术是否可以用于提高页面加载的性能。 这是我长期以来一直坚持的一个前提,它绝对正确,但这个前提在这个线程中受到了质疑。 所以任务#1 是回答这个问题。

如果我们发现脚本标签只是比脚本加载更好,那么我们可以停止所有这些疯狂并关闭我们所有的项目。 不过,我怀疑情况并非如此。 ;-)

任务#2 是一劳永逸地找出脚本连接是否总是比并行加载更好。 同样,我的前提(和我的测试)表明将所有文件合并为一个是好的,但是您必须将该大文件分成 2-3 个大致相等的部分并并行加载这些块。 因此,我们也确实需要测试该理论。

如果我们发现 script-concat 总是最好的,那么当您考虑到大多数站点从多个位置加载脚本(来自 Google CDN 的 jquery,来自谷歌的谷歌分析,facebook/twitter/g+ 按钮)时,脚本加载器仍然很有用, 等等)。 因此,作为任务 #3,我们需要确定 concat 是否更好,以至于您应该托管所有这些文件的自己的副本,并将它们与您自己的代码连接在一起。

直接回复此邮件或在 GitHub 上查看:
https://github.com/paulirish/html5-boilerplate/issues/28#issuecomment -1772315

有人会认为物理学说 concat 是最好的。 每个新的 HTTP 连接都是 CDN 的另一个慢启动 + 100 毫秒税,在更糟糕的情况下。

然而,关于文件的真相是它们可能很长。 因此,在头部加载一个 BFJS 文件可能会不必要地减慢模块的初始化速度。 最后加载它会导致烦人的 FOUC。 可能对大文件有移动影响: http :

我认为这就是 Souders 的“拆分有效载荷”规则背后的动机(http://oreilly.com/server-administration/excerpts/9780596522315/splitting-the-initial-payload.html)。 我们也需要做明显更快的事情。

不幸的是,这归结为一个“视情况而定”的答案,这使得这个问题足够有趣,让我们所有人都感到开心。

我正在尝试一种混合方法,其中 getJS 调用按设定的时间间隔定期排队和连接,以及连接模块依赖级别(例如连接 RequireJS 依赖项而不是一次加载一个),一切都在前端进行。

正如你所指出的,这是一个科学实验,希望很快就会毫无意义,但仍然很有趣。

@getify :我知道这在这一点上几乎只是在游行中

如果我们发现脚本标签只是比脚本加载更好,
那么我们就可以停止所有这些疯狂并关闭我们所有的项目。
不过,我怀疑情况并非如此。 ;-)

我可以说很多关于蛇油的事情,但演示也同样有效:

http://jashkenas.s3.amazonaws.com/misc/snake-oil/labjs.html

http://jashkenas.s3.amazonaws.com/misc/snake-oil/vanilla.html

这是一个包含 100k 文本、10 个图像和 171k JavaScript 的页面。 vanilla 版本使用一个包含 jQuery、jQuery-UI、Underscore 和 Backbone 的缩小文件,以及写出加载时间结果的timer.js文件。 LABjs 版本使用 LABjs 加载 5 个(单独缩小的)JavaScript 文件中的每一个。

您会发现 LAB 版本不仅没有任何好处,而且额外的 HTTP 请求只会损害加载性能,并且必须与页面上的其他资产(如图像)竞争。 但这一切都已经说过很多次了……

LABjs

Vanilla

我可以预料到会出现关于零碎加载脚本的反驳……但这与脚本加载技术完全正交,所以请不要讨论它。

无论如何,停止疯狂。

@jashkenas Full,100% 确认。 脚本加载器只会增加开销、复杂性和故障点。 就纯传输时间和 JavaScript 解释器的效率而言,单个服务器连接文件加载速度(est),并且作为奖励,如果您只有一个文件,gzip 压缩效果会更好。

我不得不说,LABjs 版本_有时_在我的浏览器中加载速度更快(与普通页面相比),但不一致。 另外onload并不总是触发,这似乎......奇怪。

是的,gzipping 可以让您以更少的 HTTP 请求获得更多的整体胜利。

这与教条无关,它不必是整个应用程序的 _single_ JS 文件 - 两个或三个带有defer文件对于细粒度缓存很好,稍后加载更多。

Google Page Speed 团队的一些研究:

http://pagespeed-velocity2011.appspot.com/#8见幻灯片 8-14,这使讨论更具不确定性


我仍然热衷于脚本@defer属性,并认为这是一个明智的基本默认设置,除非您计划

@miketaylr :是的,请多次切换刷新每个页面以获得整体感觉。 S3 延迟和图像加载会让事情变得有点不可预测——表现得更像一个真正的应用程序。

好吧,即使使用 shift-refresh 或缓存元素,labjs _always_ 在我的浏览器(Safari 5.1)中加载速度也最快。

当然,使用不连接的脚本加载器会比连接的脚本标签慢。 这就是为什么人们(YUI、requireJS)创建脚本加载器来加载连接文件和服务,根据请求连接它们(https://github.com/rgrove/combohandler)。

来吧,这个讨论没有任何意义。 脚本加载器用于按需加载脚本,特别是在用户交互之后,例如在单击“登录”按钮时加载对话框背后的逻辑和表单验证。

偷偷地怀疑@madrobby过于简单化了。
史蒂夫建议并行下载对一系列阻塞问题和浏览器有几个好处_(是的,这意味着非 WebKit)_。 他还提到了一种策略,即加载 dom-load 任务所需的最低限度的 JS,然后根据需要加载其余部分。 因为情况和开发需求各不相同,我不知道脚本加载器是否属于样板_(默认启用)_,但我现在还不会把婴儿和洗澡水一起扔出去。

如果在我原来的帖子中没有说清楚。 我倾向于同意(与 jdalton),脚本加载器在高度测试和需要特别注意的特定环境中有很多好处。 我不认为这是一个合适的默认值。

我同意@jdalton :没有适合所有尺寸的加载器。 我个人根据我的实际需要和项目使用不同的脚本加载器。 有时像 yepnope 或 LabJS 这样简单的东西就可以了,其他的,RequireJS 是天赐之物。 我不确定样板是否必须强行插入。这很棘手,因为我们的想法是让样板可以轻松切换到脚本加载器......所以我不会把婴儿和洗澡水一起扔出去然而。

另外, @getify假装所有脚本加载器实际上在

物有所值...
这个

var script = document.createElement('script')
script.src = 'foo.js'
document.getElementsByTagName('head')[0].appendChild(script)

比这更好

<script src="foo.js"></script>

一个主要原因是它是非阻塞的。 因此,后续的图像和 CSS 文件将需要等到该文件与后一个版本一起下载。 前者是异步的——这一点,无论你是否决定使用脚本加载器,每个人都应该知道。

回复:“假装所有脚本加载器实际上在底层使用相同的技术是一个非常不知情的声明。”

如果他们没有按照上述方式做,他们就做错了

好吧,公平地说,使用appendChild已经失宠了......:D

但是,我将该测试用例添加到 AssetRace

https://github.com/SlexAxton/AssetRace/blob/master/asyncconcat.html

它使加载速度更快,因此_可能_有一些明显的好处。 但是完成时间几乎相同......

@ded :我们不是在谈论<head>无能的大阻塞<script>在这里......我们在谈论带有deferasync脚本标签<body>的末尾,没有什么可以阻止的。

@jaubourg--

另外, @getify假装所有脚本加载器实际上在

这是对我所了解的完全错误的表述。 事实上,就使用最好的技术而言,大多数脚本加载器并没有做我认为他们应该做的事情(而 LABjs 现在是)。 我的观点是,即使他们所有人都使用了最好的技术,我们在技术方面可以做的事情仍然是有限的。 我很确定那里没有装载机正在使用一些 LABjs 不知道或不使用的神奇银弹。 无论你做什么或如何摆弄数字,你都无法让光速超过光速。

争论背后的技术(通过说“嘿,看看我的酷和更好的 API”)是没有意义的。 脚本加载中最好的技术是已知的有限数量(即使很多加载程序不负责任并且没有使用它)。 我们可以推动更好的技术(我就是),但是争论谁在他们的加载器上拥有更好的 API 对这个目标没有任何帮助。


这个线程似乎在尝试确定脚本标签本身是否足够好(有或没有延迟)或者脚本加载器是否有助于获得更好的性能方面最有意义。 其次,我们需要弄清楚 concat 是否真的是脚本加载的最终目的。

这也是一个有争议的问题(对于这个线程),脚本加载器有他们可以做的所有其他用例,而标记脚本标签不能做(比如按需/延迟加载)。 同样,在这一点上这基本上是给定的,所以试图重新建立这个事实是没有意义的。

没有你

负载愤怒!

loaders make me rage

在此处查看原始帖子。

另外,任何被卡通阴茎冒犯的人/人:欢迎来到互联网! 我强烈建议您从这里开始您的旅程

好的,我已经创建了 3 个测试来说明一些要点。 首先,手动脚本标签(作为基线):

http://labjs.com/dev/test_suite/test-script-tags.php

请注意,在脚本完成后,DOMContentLoaded(又名“DOM 就绪”)来得很晚。 这是坏处。 虽然页面的实际加载时间可能与后面的测试相同,但如果 DOM-ready 被阻止,页面的感知加载时间总是会慢得多(许多站点等到 DOM-ready 才附加点击行为,将 JS 驱动的增强应用于内容等)。

现在,我们在脚本标签上使用defer

http://labjs.com/dev/test_suite/test-script-defer-tags.php

好吧,那很好,我们已经修复了 DOMContentLoaded 延迟问题,但现在我们还有另一个问题。 内联脚本块不适用于defer 。 它立即执行。 哎呀。 顺便说一句,这不是错误,规范专门规定了这一点。

http://labjs.com/dev/test_suite/test-LABjs.php

defer测试相比,LABjs 测试获得了基本相同(或更好)的性能数据,但它不会在脚本完成后运行内联代码。

在现代浏览器(Chrome 13、FF5 等)中多次尝试这些测试。 对我来说,LABjs 的表现总是与defer测试大致相同或更好。 在我所有的尝试中,我从未见过 LABjs 的表现比defer测试差。 在较旧的浏览器(如 FF3.5 或 IE7)中尝试这些测试,您会发现脚本加载器开始以显着的数量胜过其他测试。

尽管 LABjs 测试的数字与最新浏览器中的defer测试相似,但如果defer不能用于defer ALL 代码(仅适用于对于通过外部文件加载的代码)。 许多站点加载脚本,然后有内联代码来激活/初始化他们刚刚加载的代码。 defer没有为此提供任何解决方案。

因此, defer不适合作为“通用脚本加载”技术。 下一个最佳选择是脚本加载器。

@getify

这不仅仅是关于微观优化......而且,是的,API 很重要,并且通常很好地表明了底层技术所具有的限制,主要是因为所述微观(甚至宏观)优化。 这并不总是只是加载脚本。 复杂的依赖管理、适当的沙箱和实际的、真实的、模块化并不是因为你对它没有任何兴趣就可以洗掉的。 你猜怎么着? 这些实际上是人们需要的东西,使用静态脚本标签可以在相当不错的水平上实现页面加载性能。

最后归结为脚本标记注入不是完成任务的合适工具:它实际上从来都不是。 这只是一个非常丑陋的黑客。 从这个意义上说,你实际上并不是在推动更好的技术:你在推动更多相同的技术,但我们还没有人能推断出新的警告。 请想一想,看看它是否最终点击。

真正令人气愤的是,您拒绝提供一个支持脚本标记注入的单一参数,而不是使用适当的、本机的、javascript API 来加载脚本。 你只是忽略了整个事情。 不过,我会为您省去麻烦:那里没有争论。 但是,呵呵,我们都可以对 defer 和 async 的来龙去脉进行一些心理自慰,感觉我们是 javascript 之神,对吧? 或者讨论 50 毫秒优化,就好像它实际上帮助了这个行业的任何人一样。

如果您最终确定我值得得到足够聪明的回复(而不是另一个 LabJS 广告),请在我的博客上这样做,让我们单独保留这个线程。 谢谢你。

@jaubourg——
我昨晚深入阅读了您的帖子。 我打算写一篇博客文章作为回应,主要是赞扬和赞美你在那里提出的好想法。 不幸的是,您的建议已经被 W3C 和 WHATWG 上的讨论线程的成员在 LENGTH 上进行了讨论。 你参加那个派对已经很晚了。

有几个人支持全新的加载器 API,并且有几个重要的反驳论点为什么这可能不是最好的方法。 同样,我打算在一篇仔细而合理的博客文章中写出对您的回应,以帮助解释这一切。

太糟糕了,你必须去这里做个混蛋。 现在这让我觉得那篇理性的博客文章只会浪费时间。 你显然认为我是个白痴,从来没有考虑过你想提出的问题。 因为我去年大部分时间都没有完全沉迷于脚本加载器技术以及如何获得规范和浏览器以使其更好。 是的,我是个白痴。 显然,我之前从未想过脚本标签以外的任何东西。


你显然没有听我说过的 15 次_这个_线程有更好的目标,专注于保罗爱尔兰和亚历克斯塞克斯顿提出的具体问题: defer足够好? 脚本连接比并行加载更好吗?

这些是更重要的问题。

不是使用什么底层“加载器”技术。 有一个不同的更好的论坛来讨论底层加载器技术是什么。 我明白了,你不喜欢脚本标签。 美好的。 在 W3C/WHATWG 列表上花费数十个小时,试图让 Ian 和其他人倾听您的意见。 他们可能都会打个哈欠说“我们已经解决了,走开。”

@getify :创建荒谬的稻草人测试不会为您赢得积分,伙计。 我们都知道顺序脚本标签会阻塞页面。 我们还知道,在“延迟”脚本之前运行内联脚本块对于真实站点来说无论如何都不是问题。

如果你测试是为了确认一个预先的误解……你的测试总是会确认那个误解。 争论从来都不是关于 20 个脚本标签与 20 个 LABjs 脚本加载。 它是关于在尽可能少的 HTTP 请求中智能地修剪、连接、缩小、gzip 和加载您的 JavaScript,然后缓存它。

一方面,我们有一种可靠的、受浏览器支持的、经过时间考验的方法,它在现实世界的页面上表现得明显更好; 另一方面,我们有一个被黑客攻击的“技术”,它在过去实际上已经破坏了在浏览器更新后使用它的每个站点,平均性能明显更差,并且速度差异更大。

这是一个明智的选择。

@jashkenas--

我们还知道,在“延迟”脚本之前运行内联脚本块对于真实站点来说无论如何都不是问题。

呃...我猜你还没有在互联网上大约 98% 的站点上查看源代码,这些站点实际上在标记中使用内联脚本块来执行/初始化它们之前加载的代码(阻塞)脚本标签调用。

如果@paulirish认为defer已经足够好并且不需要脚本加载器,那么我觉得有必要指出为什么实际上defer不够好。

你可能只关心你控制的几个小众站点,你完全有能力对构建过程等进行高度优化。另一方面,我关心帮助提高互联网长尾站点的性能,那些站点有六个脚本标签(其中一些是内联脚本块!),使用六个$LAB.script()调用实际上可能会提高性能。 这就是 LABjs 一直以来的意义所在。 仅仅因为它不是你关心的并不意味着它不相关。

争论从来都不是关于 20 个脚本标签与 20 个 LABjs 脚本加载。

该线程中的争论是关于 3-4 个脚本标签(带或不带defer )的性能是否比使用并行脚本加载器动态加载的 3-4 个脚本更差、相同或更好。 我的“荒谬的稻草人测试”实际上就是为了测试这一点。

根据我的经验,脚本加载器将页面加载时间缩短了许多毫秒。 但我认为我们都没有抓住重点。 JavaScript 有一些更大的问题:

  • 缺少导入语句使得以模块化方式组织代码变得困难
  • 全局变量发生冲突,除非非常注意对所有内容的仔细命名空间。
  • 无法清楚地看到脚本的依赖项是什么

我不使用 RequireJS 因为它加载速度更快,尽管这是一个很好的副作用。 我使用它,所以我可以像在 NodeJS 中一样将我的 JS 应用程序组织成小模块。 每个模块都清楚地列出了它的依赖项,并使用沙箱模式来保持全局命名空间的整洁。 模块(及其依赖项)可以预先加载,或者按需加载(例如用户点击),或者延迟加载。 你真的可以用这些技术来微调你的表现。 RequireJS 还附带了一个构建工具,可以将所有依赖项组合并缩小到一个(或几个)gzip-ready 文件中以进行部署。 解决这三个问题对我来说是一个巨大的胜利。

我可以理解为什么人们会争论使用不能解决这些问题的脚本加载器。 如果性能是唯一的点,并且值得商榷,那么肯定。 但是使用像 RequireJS 这样的 AMD 模块加载器,争论就变得无关紧要了。 模块是 JavaScript 的未来。 Mozilla 的 Dave Herman 正与 Apple 和 Google 的董事会成员合作,为语言本身添加

@getify

你不能指望人们对待你的方式与对待他人的方式不同。 光顾不是获得体面反应的聪明方式(上帝是你光顾的)而且,就像我在我的博客文章中所说的那样,我不认为你是一个白痴,我只是认为你很痴迷(你说顺便说一句,你自己)并且它严重损害了你的判断力。 就像我在我的博客文章中所说的,处理这个问题的不是 W3C 或 WHATWG,而是 EcmaScript 本身:这不是浏览器问题,而是语言问题。 现在,如果您不想回复,请不要回复,这是您的特权。

也许我来得很苛刻,但我只是捍卫我的信仰。

我将退订此线程并再对其进行评论。 很抱歉让@paulirish和@SlexAxton 出轨。

@getify

您可能只关心您控制的少数利基网站,您拥有
完全能够对构建过程等进行高度优化。
另一方面关心帮助提高长尾站点的性能
互联网,带有六个脚本标签的那些(其中一些是内联脚本
块!),实际上可能会使用六个 $LAB.script() 调用
提高性能。 这就是 LABjs 一直以来的意义所在。 只是因为
这不是你关心的并不意味着它不相关。

如果 LABjs 是为了帮助平庸的网站加载稍差一些......我想这是一个崇高的目标。 但是,如果您认真对待加载缓慢的网站,并让它尽可能快地加载——可能比 LABjs 允许的速度快几秒钟,那么您应该保持开放的心态并承认更容易和更不脆弱的网站技术也更高效。

这个线程中的争论是关于 3-4 个脚本标签(有或没有 defer)
与使用动态加载的 3-4 个脚本相比,性能更差、相同或更好
一个并行脚本加载器。 我的“荒谬的稻草人测试”实际上是为了
测试正是如此。

该线程中的争论是关于如何构建一个网站以尽可能快地加载和执行其 JavaScript。 向客户销售蛇油,并将其推广给网络开发人员,对双方都是不利的。

互联网上存在延迟。 连接、缩小和 gzip 您的 JS,并在尽可能少的 HTTP 请求中将其加载到页面底部。 纳夫说。

@jashkenas--

如果 LABjs 是为了帮助平庸的网站加载稍微不那么糟糕……这是一个崇高的目标,我想

在过去的 2 年里,我个人知道有数百个站点,它们只是用$LAB.script()调用替换了它们的脚本标签,并且总体上它们都看到了更好的性能(有些非常显着,有些只是适度)。

有一些文章(完全独立于我,与我无关)专注于帮助各个行业(如电子商务、房地产等)的网站获得更好的性能(因为更好的性能意味着更多的转换),这些文章推荐给那些他们用 $LAB 调用替换了脚本标签,这些评论线程中的许多人都肯定地回答说它帮助了他们。

如果这些文章说“好吧,你需要做的是获得更高的性能是聘请一个了解 gzip 并且可以安装 ruby​​ 或 node.js 的服务器管理员,这样你就可以执行一些自动化的构建过程......”那些人阅读这些文章会眼花缭乱,不假思索地离开。 但我喜欢相信“嘿,用 script() 替换 <script>”对他们来说是一个非常容易理解和联系的信息。

我想要的 LABjs 是一个简单的解决方案,有人可以轻松地替换他们的脚本标签,而无需过多思考。 我认识到,如果您可以亲自咨询网站并找出最佳优化方案,您就可以从许多网站中获得更高的性能。 但我也认识到,这远远超出了我作为一个人为互联网长尾做的能力,同样告诉所有那些妈妈和流行网站“嘿,去获取一个自动构建系统,并确保它使用 gzip”就像对他们说外语。 OTOH,说“嘿,拿这 3 个脚本标签,让它们进行 3 个 script() 调用。看看这有多容易?”是非常成功的吗?

最重要的是,我使用 LABjs 的方法是实现低垂的果实。

这并不是说更复杂的优化方法是不可能的——它们显然是,当我有机会咨询时,我肯定会探索它们。 只是说对于很多网络来说,它比他们愿意或能够得到的更复杂/更复杂。 我只是想帮助_那些_网站以一种更容易让他们掌握的方式进行改进。

@jashkenas--

可能比 LABjs 允许的速度快几秒钟,那么你应该保持开放的心态,并承认更简单、更不脆弱的技术也更高效。

从来没有任何既定的证据表明 LABjs 显着降低了任何网站的速度。 有大量既定证据表明它正在帮助许多网站。 所以我不买这个——你说的是一个假设没有证据的错误前提。

@paulirish发现了一篇指出defer属性问题的帖子:
http://hacks.mozilla.org/2009/06/defer/

从移动性能的角度来看——就像@jashkenas所说的那样,最好将它连接起来、gzip 并作为一个包通过线路发送,而不是由于 3g 网络连接引起的延迟而具有多个 http 请求。

在利用内联技术方面进行了大量研究,您可以将图像 base64 编码为字符串,然后将它们作为key:value对存储在 localStorage 中,以减少 http 请求并利用“缓存”: http : Mickens的精彩演讲。

这是一个非常好的关于 http 请求的移动性能及其对用户体验的影响: http :

我在RequireJS 上工作,我想澄清一下 RequireJS 的目标:

1) 展示 JS 中模块化代码的方式,在 JS 运行的任何地方都能很好地工作。
2) 加载脚本。

“加载脚本”部分是实现第一个目标的必要部分。 在开发中,将所有脚本连接起来并不是一个好主意,因为这会使调试变得更加困难,行号不匹配。 脚本加载器还可以轻松地使用 JS API 按需加载代码。 对于网络邮件大小的应用程序,这是性能故事的必要部分。 但是,将脚本连接成一个或少数几个请求通常是最好的部署选项。

但是 requirejs 的目标是成为 shim/polyfill/whatever 以展示如何创建和引用可以与他人共享的模块化代码单元,这种方式不鼓励全局变量并鼓励显式依赖。

它使用AMD API ,该与其他人一起制作模块化脚本加载器(包括合规性测试),目的是帮助为 JS 中的模块格式的任何讨论提供信息。 这种方法,通过在现实世界中实现并与其他人就 API 达成一致,是取得进展的方式。

特别是,考虑到 JS 的网络性质及其与 Web 文档/应用程序的关系,加载器插件 API应该以某种方式被 ES Harmony 模块支持,我正在通过requirejs loader 插件,所以我可以更好地理解和声建议并提供反馈。

对于表演的人

  • 支持 AMD 的加载器有多种选择( curlDojo 1.7loadrunner 、requirejs),甚至是一个非常小的加载器,可用于“一个 JS 文件中的所有脚本”优化部署。 因此,可以在鼓励最佳编码实践的同时获得出色的性能——通过避免全局变量、使用显式依赖项来更轻松地共享代码。
  • requirejs 优化器在 Node 中运行非常快,在 Rhino 中也可以运行。 它是一个命令行工具,但最新的 master 分支代码将其导出为可在 Node 中使用的模块,因此例如,它可以通过基于 Node 的 http 服务器运行,该服务器可以即时进行构建。 因此,如果您愿意,您始终可以在“始终下载一个脚本”模式下进行开发,然后选择从优化文件中删除一两个模块,以便您可以轻松调试它们。

在这张票的上下文中:选择符合 AMD 标准的加载器(不一定是 requirejs)符合 HTML 样板的目标:指出代码和性能方面的最佳实践。 然而,我很欣赏尝试制定 HTML 样板是一件非常困难的事情,存在相互竞争的利益,有些风格,所以我很感激此时不想在这方面提出建议。

我只想说清楚,实现 AMD API 的 requirejs 和加载器的目标比仅仅加载一些转储全局变量并强制开发人员计算出完整的、有时是隐式的依赖树的脚本提供更大的好处。 这些目标是通过具有可靠性能配置文件的解决方案实现的。

重新关注之前......将defer测试与 LABjs 测试进行比较......(并忽略defer不适用于内联脚本块的事实),是否有人看到LABjs 测试的表现比defer测试差吗? 我已经在一堆浏览器上尝试过,甚至在我的移动设备上,仍然看到大致相同的数字。

http://labjs.com/dev/test_suite/test-script-defer-tags.php

http://labjs.com/dev/test_suite/test-LABjs.php

@getify

我不知道为什么或如何优化它,但在我 3 岁以上的 MacBook 机器上,两者之间的差异始终为 3000,这有利于@defer

但是,我只用 Firefox 进行了测试。

@espadrine--很奇怪。 很想深入了解这一点。 您正在测试哪个版本的 Firefox? 你能把结果的截图发给我吗?

只需连接并缩小您所有的 JS 和 CSS,然后将其内联到您的 HTML 页面中即可完成。 单个 HTTP 请求 FTW! :P

不过说真的,在这个社区中,我们应该关注许多更大的问题,而不仅仅是您的应用程序将如何加载。 有可能,最简单的方法(底部的脚本标签)可能已经足够快了。 只需编写出色的应用程序并在最后处理加载性能。 做任何其他事情都是过早的优化。

在这个线程上,人们是否普遍认为 AMD 应该成为 JS 代码组织的黄金标准? 还没有真正看到其他选项,但我同意 Boilerplate 将是一个很好的开始,可以让人们正确地组织代码。

Firefox UX 8.0a1 (2011-08-07) 更新频道。

defer
LABjs

同样,不知道为什么,这可能非常具体。 LABjs 可能非常适合旧版浏览器。

请不要使用@getify的测试页面来逗笑。 报价:

<script defer src="http://labjs.xhr.me/dev/test_suite/testscript1.php?_=4911710&delay=5"> <script defer src="http://labjs.xhr.me/dev/test_suite /testscript2.php?_=6146431&delay=3"> <script defer src="http://labjs.xhr.me/dev/test_suite/testscript3.php?_=9499116&delay=1">

@getify ,如果你想进行真正的测试,请随意 fork @SlexAxton的 AssetRace 存储库并添加一个 LABjs 版本……或者制作一个使用 _real_ 的 JavaScript 文件的测试页面,具有真正的延迟。

另外,请确保您实际上将 JS 连接到单个脚本标记 - defer与否。 关键是通过 1 个 HTTP 请求提供的相同内容胜过通过 10 个 HTTP 请求提供的相同内容。

从未有任何既定证据表明 LABjs 显着
减慢任何网站的速度。 有很多既定证据表明它有很大帮助
的网站。 所以我不买这个——你说的是一个错误的前提假设
没有证据的事实。

上面展示的是 LABjs 确实显着减慢了网站的速度,让他们的 JS 与他们的图像、CSS 和其他资产在许多 HTTP 请求中竞争。 @getify :我很想看到一个站点的链接,您认为该链接在您将其转换为 LABjs 中得到了极大的展示。 也许我们可以下载它的副本,并将其用作您会尊重的测试用例。

作为记录,我认为在 AssetRace 存储库测试页面中获取更多图像是明智的。 但这现在肯定是一个很好的基线。

@artzstudio使用 AMD 加载器组织您的 JS 确实是黄金标准,至少在 Harmony 的模块完成并得到广泛支持之前是这样。 那么就会有清晰的从 AMD 模块到 Native 模块的迁移路径。

AMD 模块是黄金标准当然是一种意见(我可能会分享)。 但是,有很多聪明人(想到 Yehuda Katz 和 Dan Webb)不喜欢它并提供其他解决方案。

@danwrong的 loadrunner 可以同时做这两件事,如果那也是你的包: https :

里面有一些不错的东西。 对于非 JS 人员来说,也可能更实用一些。 我喜欢 AMD 模块作为我的东西,但并不是每个人都愿意花时间转换他们用作模块的每个版本的库。

我知道@strobecorp正在开发他们自己的解决方案,该解决方案不需要 AMD 模块所需的大量额外代码。

虽然我希望 AMD 成为默认设置,但从多库/newb 的角度来看,这可能并不明智,正如我所希望的那样。

@jashkenas--

请不要使用@getify的测试页面来逗笑。

如果你不能有礼貌,我不想和你进一步讨论任何事情。 我是真诚地行事。 我会很欣赏一点共同的体面。

@getify ,如果你想做一个真正的测试

我肯定希望你解释为什么我所做的如此疯狂、可笑和无效。 我直接采用了 Steve Souders 的方法,他(以其丰富的经验和智慧)在他的所有测试中建议您使用服务器计时来控制脚本,从而减少测试中的差异量。 这正是我正在做的。

更受控制的测试是有效的基线测试。 这是既定的科学实践。 这并不意味着现实世界的测试也没有用,但这也不意味着你可以狙击我并说“笑他,真是个白痴,因为他的测试方式与我认为的不同需要被完成。”

随意 fork @SlexAxton的 AssetRace repo 并添加一个 LABjs 版本

我会很乐意这样做。 但不是因为我同意我的其他测试无效。 如果您对为什么我的测试设置无效有一些合理的、冷静的论点,请分享。 但是不要对它这么胡说八道。

@jashkenas--

关键是通过 1 个 HTTP 请求提供的相同内容胜过通过 10 个 HTTP 请求提供的相同内容。

我知道你(和其他人)一直在这里咆哮,讨论这个讨论应该是关于 concat 还是 not-concat。 如果您在线程的前面阅读了很多内容,我承认有两个问题需要解决。 就我而言,这两个问题是正交的。 第一个是标记中的脚本标签是否可以与并行脚本加载器中使用的动态脚本元素一样好(或更好)。 这个问题是我仍在尝试通过测试解决的问题。

第二个问题,我们还没有解决,是关于 script-concat 是否总是更好。 我知道你已经相信了,但我有相反的证据表明它并不那么简单。 这个问题也需要彻底测试。 但这不是我现在在这个线程中想要解决的问题。

通过继续坚持你的方式是更好的方式,你只会让整个辩论变得不那么愉快。 我要做的就是有条不紊地为这两个主要问题中的每一个建立一些证据,这样我们就可以停止猜测并获得更多信息。 为什么那不是你可以帮助的事情,而不是因为你不同意我而试图成为我的混蛋?

关于defer测试与 LABjs 测试,我只是做了一个快速截屏,在 IE9、FF8(每晚)和 Chrome15(金丝雀)中对这两个测试进行了正面测试。

http://www.screenr.com/icxs

要回答@paulirish之前关于defer怪癖的问题 (https://github.com/paulirish/html5-boilerplate/issues/28#issuecomment-1765361),请查看“DOMContentLoaded”在 IE 中的表现, defer测试中的 Chrome 和 Firefox。

在 IE9 和 Chrome15 中,DOMContentLoaded 事件被阻止(阻止)并且直到脚本运行后才会被触发。 然而,在 FF 中,DOMContentLoaded 事件不会被阻止,它会立即触发,然后脚本开始执行。 这是现代浏览器之间的巨大不一致,也是我认为defer不够用的原因之一。

据我阅读规范可以看出,我不确定哪种行为是正确的。 但我确实知道它在浏览器之间显然很古怪且不一致。

@getify我不想成为一个混蛋。 我真诚地道歉,我伤害了你的感情。

当然,你认为的咆哮,我认为是讨论的重点……而我认为的蛇油,你认为是向前迈出的有益一步。

这两个问题确实是正交的(我在原帖中使用的语言)。

第一个是标记中的脚本标签是否可以和(或更好)一样好(或更好)
并行脚本加载器中使用的动态脚本元素。

我们在这个问题上完全一致——没关系。 当然,对于多个脚本,并行加载会比顺序加载更快。 当然,以非阻塞方式进行操作,无论是在<body>标签的末尾,还是使用defer ,或者使用脚本加载器,都比在<head>阻塞要好

但这没有抓住重点。 放入连续的脚本标签是一个比较的稻草人,因为没有人关心他们的 JavaScript 的性能会使用这种方法。 猜猜还有什么比顺序脚本标签更快? _任何事物_。

第二个问题,我们还没有得到,是关于是否
脚本连接总是更好。

我们已经“开始”了这个问题。 事实上,这是本页顶部的

这个问题也需要彻底测试。

重复一遍,这是一个(公平的)测试用例。 相同的 5 个真实世界的脚本,加载到一个中等大小的页面,其中存在其他资产,一个使用 LABjs 最佳实践来确保加载顺序,另一个使用单个串联脚本:

http://jashkenas.s3.amazonaws.com/misc/snake-oil/labjs.html

http://jashkenas.s3.amazonaws.com/misc/snake-oil/vanilla.html

如果您有其他想要检查的测试用例,或者想要尝试使用真实世界的 LABjs 网站,请分享。

@SlexAxton谢谢。 我很想听听 Yehuda 对此的看法和其他强烈的意见(除了它很难重构)。 我找到了这个,但不是谈话。

澄清@geddesign的评论:截至今天,看起来 AMD 模块可以很容易地转换为和谐模块,但我认为和谐模块提案仍在不断变化,以后可能会改变。 它尚未通过严格的实施测试,但已开始有所作为。 从好的方面来说,AMD 加载器 + 加载器插件可以为尝试一些和谐的想法提供可靠的反馈。

@SlexAxton的评论:

对于 loadrunner:我不清楚语法是否更好,只是不同。 它支持 AMD,所以它仍然有效。

对于频闪:我还没有看到他们的代码。 他们似乎相当内向,尽管我很欣赏 Yehuda 为开放这一发展所做的工作。 亚历克斯,如果你能指出他们在想什么,我将不胜感激。

如果该方法将允许嵌套依赖项(这是广泛代码共享所必需的),则您需要一种语法:

  • 给代码单元命名
  • 一种指定依赖项的方法
  • 围绕该代码的函数包装器,以确保它在依赖项准备就绪之前不会执行。 或者总是要求构建或 XHR 访问,这在 JS 开发的范围内是不可扩展的。

这就是 AMD 提供的,并且语法尽可能精简。 其他任何事情都只是在争夺名称和某些类型的标点符号。 在某些时候只需要选择一些东西,到目前为止,我还没有从 Dan Webb 或 Yehuda 那里听到有关使 AMD 站不住脚的结构性弱点的消息。 一些 AMD 加载器,比如 requirejs 可以只加载常规脚本,它们不必是模块。

想出代码语法是很容易的,特别是对于模块,我可以理解每个人都有自己的个人喜好。 然而,AMD 在努力达成某种协议方面有着相当深厚的历史,更重要的是需要真正的代码和部署来支持它。 我觉得现在其他人有责任真正清楚清楚为什么 AMD 不合适(这张票不适合它,请随时与我联系,或使用amd-implement列表) .

但我很欣赏@SlexAxton的观点。 对 HTML 样板采用 AMD 方法进行标准化可能为时过早,我对此完全没有意见。 如果样板项目决定选择一个,AMD 是一个适合广泛 JS 开发的强大选择。

@SlexAxton我和你在一起。 我自己的代码一路都是AMD。 虽然我希望每个人都编写模块而不是脚本,但幸运的是 RequireJS 可以加载普通脚本和模块。

如果您指的是 Yehuda 的 handlebars.js 模板,那么它们与 RequireJS 一起工作得非常好。 特别是如果您编写一个插件来编译/缓存模板并返回其模板函数。

define(['tmpl!navigation.html'], function(nav){
   $('body').append(nav(data));
});

不过我不同意这个说法:

虽然我希望 AMD 成为默认设置,但从多库/newb 的角度来看,这可能并不明智,正如我所希望的那样。

Newbs 比经验丰富的开发人员更需要 AMD 提供的干净结构,因为他们更容易发生全局变量冲突,糟糕的代码组织导致巨大的凌乱 JS 文件,没有人因为害怕不得不处理合并冲突而不想碰这些文件,等等。库从模块中受益匪浅,这就是即将到来的 Dojo 1.7 和 Mootools 2.0 迁移到 AMD 的原因。 我希望 jQuery 加入进来——它最大的抱怨之一是它是“全有或全无”。 如果不同时将其动画、ajax、事件等加载到页面上,就无法使用其出色的 DOM 操作。 所以是的,AMD 是双赢的。 如果 HTML5 Boilerplate 想要向人们指出最佳实践,那么忽略 AMD 将是一种耻辱。 它优雅地解决了 JavaScript 的许多问题。

要清楚。 我同意。 我希望他们一直使用 require 。

我只是不认为他们会。

我认为人们还没有意识到 AMD 是一个流行语,每个认真的开发人员都需要了解的“事物”。 一旦他们这样做了,他们就会想对他们的老板和未来的面试说他们知道并使用它。

如果我们都尽自己的一份力量说“看,这很容易,更好,而且很重要”并使其成为流行语,那么牛群就会为了他们的职业而效仿。

@jashkenas--

第一个是标记中的脚本标签是否可以与并行脚本加载器中使用的动态脚本元素一样好(或更好)。

我们在这个问题上完全一致——没关系。

实际上,我开始参与这个主题时假设每个人都同意动态脚本元素加载将导致比脚本标签更好的性能。 但是@paulirish@slexaxton都在_this_ 线程中对该假设提出了质疑。

@paulirish建议defer是使普通 ol' 脚本标签与动态脚本元素加载替代方案一样好(或更好)的充分方法。 我不同意defer就足够了,我现在已经确定了几个原因。

所以,我认为我们检查了第一个问题是有效的,并探讨了defer是否比脚本加载器更好。 可能有一些有限的情况您可以使用defer ,但就一般情况而言,脚本加载程序处理/规范化所有的怪癖,而defer会让您面临这些问题。

我仍然不确定每个人都看到或同意为什么defer是不够的。

重复一遍,这是一个(公平的)测试用例。 相同的 5 个真实世界的脚本,加载到一个中等大小的页面,其中存在其他资产,一个使用 LABjs 最佳实践来确保加载顺序,另一个使用单个串联脚本:

这是您(和其他人)的错误测试前提。 我从未声称加载 5 个脚本而不是 1 个脚本会更快。 绝不。 曾经。 我能再清楚点吗? 前提从来不是 5 对 1。

第一个测试是测试 3 个脚本标签与 3 个script()调用,因为这是一个公平的测试。 而且我认为视频和测试说明在那种情况下脚本加载是有益的。

第二个更复杂的测试问题是,是否有任何方法可以提高已经将所有 JS 加载到一个文件中的站点的性能。 大多数人说这是不可能改进的。 我不同意。

注意:这个问题是正交的原因是您可以使用脚本标记或使用document.createElement("script")类型动态加载加载这个单个 concat 文件。 无论哪种方式,单个 concat 文件的问题都是一个有效的问题,但与脚本标签或动态脚本加载是否更好分开。

你听到我在这个线程中多次说过,以及在许多其他上下文中(包括我所有关于该主题的会议发言、博客文章等),我认为你可以改进单个 JS 文件 concat通过“分块”(即将大的 concat 文件)分成 2 或 3 个块(最多)的方法。 如果块大小相等,并且并行加载,那么即使有额外的 HTTP 开销,由于连接“Keep-Alive”、并行加载效果等,页面加载速度可能会更快。

事实上,我很久以前就写过这个话题,回到 2009 年 11 月,在 LABjs 首次发布后不久: http :

在那篇博文中,从那时起,我说过如果你有能力(不是每个人都......事实上,大多数网络都不是)使用构建过程来连接,你应该这样做所以。 时期。 总是。 始终将 10-20 个本地文件的文件合并到更少的文件。

但是,我还说,一旦您拥有单个 concat 文件,尝试以 2-3 个块并行加载(使用脚本加载器)加载您的单个文件也可能是有益的。

为什么这会更好? 我在那篇博文中把它列出来,但简而言之:

  1. 并行加载效果是真实的。 向 bit-torrent 用户询问这个问题。 HTTP 开销也是真实存在的,并且会起到抵消和消除这种好处的作用。 但这并不意味着不可能受益。 使用连接 Keep-Alive,您可以获得 2 或 3 个同时连接(没有 2-3 个完整的连接开销损失),并在更短的时间内加载您的代码。 如果将其分 3 块加载,时间会缩短 1/3(快 60-70%)吗? 不。绝对不是。 但它可能快 20-30%。
  2. 在单个文件中提供所有代码可防止您为不同的生命周期代码执行不同的缓存标头。 例如,jquery 非常稳定,永远不需要重新下载。 但是您网站上以用户体验为中心的代码可能非常不稳定(您可以每周调整一次或更多次)。 在单个 concat 文件上做短缓存头是愚蠢的,因为它不必要地强制更频繁地重新下载稳定代码。 在单个 concat 文件上执行长缓存标头也是愚蠢的,因为它迫使您使缓存文件(缓存胸围参数等)无效并强制完全重新下载整个文件,当您只调整一个字节时更易变的代码。 因此,将大的 concat 文件分成 2 个块,一个用于稳定代码,一个用于易失性代码,允许您为每个块使用不同的缓存标头。 这可以更有效地利用缓存,并在一段时间内潜在地提高性能,因为用户会重复访问您的网站。
  3. 研究表明,平均而言,单个页面视图使用的 JS 远少于 100% 加载到页面上的 JS(一些估计将它放在大约 20-30% 的代码中)。 在页面加载开始时一次性加载所有代码会不必要地挤占行,以推送当时不需要的文件的 70-80%(并且可能“永远”不需要)。 如果您的代码分为 2 个块(一个是更关键的代码,另一个是不太关键的代码),并且您立即加载第一个块,并在页面加载几秒钟后加载第二个块,则可以释放用于更重要的图像/CSS 和内容的管道。 本质上,分块允许您确定代码的优先级。

底线......关于concat与并行的话题......我_总是_告诉人们:两者。

@getify说得好。

Kyle 的 LABjs 得到了我的支持。
作为帮助网站提高性能的顾问,我多次看到 LABjs 运行良好。
它不仅显着提高了性能(不仅仅是 100 毫秒,而是 1+ 秒),而且开发人员也喜欢它。
易于理解,易于实施。

我将借此机会公开表示“感谢 Kyle,感谢您对 LABjs 的大力支持。您已经多次超出我的预期。”

使用连接 Keep-Alive,您可以获得 2 或 3 个同时连接(没有 2-3 个完整的连接开销惩罚)

HTTP 不会多路复用/交错响应,因此您不能在没有首先打开多个连接的情况下进行并行下载。 持久和流水线连接的理想情况等于连续下载单个文件(+ 几个标头)。

@pornel--

我亲眼目睹并验证了浏览器可以同时打开多个连接到单个服务器,其中使用 Connection Keep-Alive,第二个和第三个连接的开销比第一个少得多。 这就是我所说的效果。

@getify太棒了,我想我们已经达成某种共识。 刷新你的记忆:

我可以预见一个关于零碎加载脚本的反驳......
但这与脚本加载技术完全正交,所以请忽略它
的讨论。

是的,我同意在与永久脚本不同的 JS 文件中加载易失性脚本很棒。 加载仅在特定页面上需要的脚本,仅在该特定页面上,同样很棒。

因此,如果我是一名 Web 开发人员并且我有一个包含大量 JavaScript 的页面,我该怎么办? 使用 LABjs,或者将我的永久脚本连接到一个文件中,并将我的易失性脚本连接到另一个文件中,并使用<script defer="true">将这两个脚本加载到 body 标签的底部?

为什么我应该让我的应用程序遇到缓存问题、浏览器不兼容、与页面上的图像竞争以及脚本加载器带来的其他麻烦?

如果使用脚本加载器提高性能的整个前提是它比使用两个脚本标签更容易和更简单......我在布鲁克林有一座桥可以卖给你。

@getify 不止一次实现了一个 web 服务器:keep-alive 不会以任何方式影响并发请求,只会降低后续请求的成本。 带有保持活动状态的两个后续请求的拆分主体仍然比单个请求更昂贵。 对两个身体部位有两个并发请求可能会表现得更好,但请记住,浏览器只会打开有限数量的并发请求(我认为取决于浏览器并配置大约 5 个),如果全部都可以您所做的是加载您的三个 js 文件,但是,正如@jashkenas 不止一次指出的那样,如果您有其他资产(如图像或 css 文件),则会出现问题。

@jashkenas-

因此,如果我是一名 Web 开发人员并且我有一个包含大量 JavaScript 的页面,我该怎么办? 使用 LABjs,或者将我的永久脚本连接到一个文件中,并将我的易失性脚本连接到另一个文件中,并使用 <script defer="true">?

TL; DR:两者

首先,网络上的许多站点都是由 CMS 组装的,这意味着在整个页面中散布内联脚本块是很常见的,并且仅通过说“将所有代码移动到一个文件中”来解决维护方面的问题非常困难。 因此,我认为 _most_ 站点可以在没有任何“内联代码”的情况下在另一个外部脚本加载和执行后运行的前提下,充其量是不太可能的。

其次,我已经证明defer DOMContentLoaded在各种浏览器中的作用与defer可能是一个问题。 尤其是它是一个存在很多误解和困惑的敏感领域,所以很快就变成了“这不是一个简单明了的解决方案”。 这需要更多的思考。

第三,我认为对于很多网站来说,将他们的标记更改为使用$LAB.script()而不是&lt;script>比向他们解释如何在他们的网站上安装一些自动(或手动)bulid 过程要容易得多。服务器。 特别是如果该站点位于共享主机上(大多数网络都是),并且他们并没有真正控制他们的大部分服务器,那么要求他们弄清楚构建过程以便他们的代码可维护性不会丢失是......好吧。 .. 不平凡。

这些事情能克服吗? 是的。 他们当然可以。 但他们需要做很多工作。 在某些情况下(比如 DOM 就绪的东西),他们实际上可能会煞费苦心地调整你的代码。 需要一个人在这方面付出辛勤的努力以及大量的专业知识和热情才能解决所有问题。

相比之下,他们可以通过 LABjs 而不是&lt;script>标签获得“快速胜利”。 他们几乎不需要考虑(除了document.write() )。 大多数时候,“它只是有效”。 大多数情况下,他们会看到页面加载速度立即增加。 对于大多数网站来说,这是一个巨大的胜利。

所以,为了回答你的问题,我想说,正如我之前所说,两者都做......首先降低 LABjs,看到一些立即的速度增加。 现在,强烈考虑使用构建过程将您从 15 个文件减少到 2 个文件(1 个文件分成两半)的好处。 当你这样做时(如果你这样做,正如我所说,大多数人不会),如果你真的想要,你可以放弃 LABjs。 但是没有真正的危害(它很小并且缓存很好,即使在移动设备上也是如此)。 它会继续很好地加载您的两个文件块,并且不会出现defer可能导致的怪癖。

此外,已经有了 LABjs 使您执行第 3 步变得非常简单,即开始弄清楚以后可以“延迟/按需加载”哪些代码。 如果没有脚本加载器,您就无法做到这一点。 LABjs 已经存在并且熟悉意味着您根本不必担心如何加载该按需脚本——它已经被弄清楚了。

@rkh--

我向我展示了它(特别是在 Apache 中,通过切换 Keep-Alive 设置)多个并行请求是如何受到影响的(当 Keep-Alive 在那里时是积极的)。 我不是这方面的专家,因此争论它如何工作的确切细节超出了我的范围。 我可以说当 Keep-Alive 存在时,请求 #2 的时间少于请求 #1 的时间。 浏览器和服务器是如何做到这一点的,我只能做出部分知情的猜测。

带有保持活动状态的两个后续请求的拆分主体仍然比单个请求更昂贵。

我从来没有争论过第二个请求是免费的。 我认为第二个请求不像第一个请求那么昂贵。 因此,如果我们假设必须至少发出一个请求,那么在开销或时间成本方面,并行执行第二个请求与具有到同一服务器的两个完全独立的连接不同。

通过估计,请求 #1 似乎是 X 的服务,而与 Keep-Alive 并行的 #2 是 0.7X。 向我解释说,服务器能够利用一些现有的连接开销来为第二个请求提供服务,从而使其便宜一些。 关闭 Keep-Alive 后,第二个请求没有这种可测量的减少。


尽管如此,所有这些讨论都是一个非常深的兔子洞。 我不是服务器专家。 我不必是。 我只能解释我实际上已经看到(并创建了测试)围绕这个确切的主题......我可以测试单个 100k 文件加载时间与并行加载同一文件的两半吗,第二个测试是否可以衡量量更快。 正如我所说的,我看到,并行分块测试的速度提高了 15-25%。 它是如何做到的,并设法以某种方式超越了可怕的“OMG HTTP 响应开销太可怕”的效果,并且仍然受益于两个并行加载,我想我没有资格进行科学证明。 但它绝对是通过观察做到的。

天啊,你们这些人打字快。 我读完,重新加载页面,还有九个评论。

我需要帮助。 我试图准确指出我们从讨论_什么最适合样板 HTML 文件_到讨论_脚本加载器是否在所有情况下都是蛇油_的确切位置。

@getify ,您当然应该为 LABjs 辩护并回应线程中其他人提出的具体批评,但是(@jashkenas 除外)我认为那些批评 LABjs 的人这样做是为了证明它不是样板的最佳解决方案。 您认为将遗留页面转换为 LABjs 比转换为script[defer]更容易,这可能是真的,但是这如何应用于样板 HTML 文件(根据定义,从头开始)?

你说它是为那些没有花哨的构建过程的人设计的,但你似乎也提倡连接、拆分成相同大小的块并并行加载。 这不是构建脚本的任务吗? 同样,对于旨在为用户提供智能默认值的样板,这似乎是错误的选择。 如果用户想要所谓的 20-30% 速度提升,她可以选择稍后升级样板提供的内容,但这不是一项微不足道的任务。

说了这么多,如果你们想继续讨论一般话题(“脚本加载器:有价值的工具还是蛇油?”),我会很高兴地闲逛并制作一些爆米花。

@getify :我同意第二个和第三个连接的打开速度可能比第一个更快——第一个连接等待 DNS,并且可能将第一个数据包路由到服务器比沿同一路径路由其余数据包要慢一些。 在 HTTPS 中,SSL 会话缓存对后续连接有很大帮助。

但是,在这种情况下,我看不到 Keep-Alive 的相关性。 同一连接上的后续 _requests_ 使用 Keep-Alive 启动得更快,但这些请求在连接内是串行的。

到这里我就快完成了——关于脚本加载器,我刚刚达到了我的“疯了,不想再忍受”的时刻。

也就是说,我认为这个线程,对于火焰节来说,实际上已经很有成效了。 如果 LABjs 想要对倒霉和无能的网站提出索赔,而让那些真正想让他们的网站快速加载的人独自一人,那么这是向前迈出的一大步。

伙计,冷静

@savetheclocktower--

公平的问题。

我并没有开始参与这个强烈主张将 LABjs(或任何脚本加载器)包含在 h5bp 中的线程。 我认为它很有用(见下文),但我失眠并不是我的主要担忧。 显然,这个线程已经演变成对所有“脚本加载”的全面攻击。 显然,这是我更关心的事情。

你说它是为那些没有花哨的构建过程的人设计的,但你似乎也提倡连接、拆分成相同大小的块并并行加载。 这不是构建脚本的任务吗?

我主张首先将所有几十个脚本标签移动到一个并行脚本加载器,比如 LABjs。 这仅需要调整标记的能力。 例如,这比告诉妈妈和流行网站使用基于 node.js 的自动构建系统要容易/不那么令人生畏。

对于那些可以构建文件的人,我主张 LABjs 仍然有好处,因为它可以帮助您并行加载这些块。 如果您完全不同意块在任何方面都有用,那么您将看不到任何理由在defer上使用 LABjs。 但是,如果您明白为什么分块 _ 可能_ 有帮助,那么应该遵循脚本加载器 _ 也可能在该过程中提供帮助。

同样,对于旨在为用户提供智能默认值的样板,这似乎是错误的选择。

唯一的原因,我认为一个脚本加载程序(特别是其中一个设计,像LABjs,有脚本标记之间的一个一对一的映射script()呼叫)在一个样板一个好处是,在一个样板,您经常会看到某物的一个实例(例如标签),并且您构建页面的趋势是根据需要多次复制粘贴复制。 因此,如果样板文件中有一个性能不佳的模式(脚本标签),人们倾向于将脚本标签复制十几次。 我认为,平均而言,如果他们多次重复$LAB.script()跟注,他们的表现很可能不会像以前那样糟糕。

这是我开始参与这个话题的唯一原因。 这是我对上面@paulirish的“盲目信仰”评论提出

呜呜呜呜是的。


我认为很明显,这个讨论已经超越了脚本加载器是否适合 h5bp 项目。 但这很好,因为这个话题值得探讨。


无论如何,我对可重现的测试用例和测试结果非常感兴趣。

似乎@defer的规范也是为了保护浏览器随之提供的一些不稳定行为。 这种行为应该被记录下来。 当它准备好时,我可以帮助将它迁移到 MDC。

我们需要关于这些行为的直接文档,以捕获所有浏览器、不同的连接类型和网络效应。 我不确定测试设备是否应该使用 cuzillion 或 assetrace,但这可以确定。

我已经设置了一张票来收集对该https://github.com/paulirish/lazyweb-requests/issues/42 的兴趣

如果您对 webperf 研究和记录证据的 _superfun_ 任务感兴趣,请加入我。

先生们,让我们考虑关闭这个线程。

正如@jrburke在他的评论中所描述的那样,延迟加载并不是 AMD 模块的核心优势。我选择尽可能多地使用 AMD 模块的主要原因是因为它改进了代码结构。 它使源文件小而简洁 - 更易于开发和维护 - 与在开发期间使用 css @import并运行自动构建以组合样式表的方式相同,也推荐用于大型项目......

我觉得我去年写的这篇文章适合这个主题:性能教条- 这不完全是关于性能,并确保你没有_浪费时间_“优化”一些不会产生任何 _real_ 区别的东西......

我和@SlexAxton 在一起,我想要 AMD 但简单的脚本标签对大多数人来说可能就足够了。 也许一个有效的方法是添加一个新设置来选择 AMD 项目并运行 RequireJS 优化器而不是 _concat_ 任务( RequireJS 优化器 Ant 任务),这会很酷,而且可能不难实现。

先生们,让我们考虑关闭这个线程。

@paulirish包括 AMD 支持怎么样? 我们应该在哪里讨论?

@benatkin开一张新票兄弟。

@paulirish好的,谢谢。 @jrburke你能开一张新票来继续你开始的讨论吗? 我想我会添加评论,但我认为我无法像您一样为 AMD 支持提供案例。

有趣且信息丰富。 谢谢你们。

我认为有人需要启动一个新的脚本加载器项目并将其称为“Issue28”。 :)

对于最广泛的兼容性,可以通过将脚本放在底部、缩小、gzip 来获得快速性能,但不要推迟。 至少在浏览器兼容性连续几年保持一致之前不会。

瓶颈可能来自广告、javascript 过多、HTML 臃肿、CSS 过多、iframe 过多、请求过多、服务器延迟、javascript 效率低下。 使用大量第三方库的应用程序存在的问题不仅是 javascript 过多,更重要的是,它们往往还有许多其他问题,主要是臃肿的 HTML、无效的 HTML、过多的 css 和低效的 javascript。 Twitter 是正确的,有两个版本的 jQuery 和两个 onscroll 处理程序,导致右列 onscroll 弹跳。

关键是,如果您知道自己在做什么,就可以避免这些问题。 您不需要 jQuery 或下划线之类的东西,因此您的脚本要小得多。 您编写干净、简单、有效的 HTML 和 CSS。 因此,您的页面加载速度更快,应用程序在更改方面更加灵活,并且 SEO 得到改进。 因此,使用脚本加载器只会增加不必要的复杂性和开销。

https://github.com/BroDotJS/AssetRage

繁荣! 我关闭俱乐部,我关闭线程。

什么线程......哇。

Imo,讨论是在 h5bp 的背景下开始的,它旨在成为网络开发人员的起点。
因此,您可以声明使用 h5bp 的 webdev 实际上将拥有干净的 HTML、干净的 CSS、良好的 .htaccess 等,并且_也许_甚至_不_遭受太多图像、低效的 JS、许多蹩脚的第三方 JS 等。你知道,因为 Web 开发人员选择使用高性能 h5bp 并且因此关注性能,并且会关注进入页面的非 h5bp 内容。

从线索来看,在这种情况下,我认为不幸的是没有足够的证据来得出最终结论。
我与保罗一起进行研究并记录需要记录的内容。
在保罗算我。

边注。 我对 AMD 不是很熟悉,乍一看,它对我来说似乎很吓人,或者至少不是我可以很容易接受的东西。 我认为大多数“普通”网络开发人员都会同意。
你在 h5bp 中看到的东西需要有一个较低的进入门槛,否则它不会被使用,并且 h5bp 的吸收可能比没有它的速度慢。
我怀疑像 AMD 这样的东西属于 h5bp。
把事情简单化。

还有一个评论......
多年来,“将脚本放在底部”和“将 JS 文件连接到单个文件中”一直在 Web Perf 最佳实践列表中名列前茅。 那么,为什么由内部开发人员和顶级品牌机构构建的平均 90% 以上的网站在 HEAD 中仍然有多个脚本标签? 真的,这是为什么呢?

其他 9% 在 HEAD 中有一个单一的、串联的 JS 文件。
我很少看到一个“普通”站点,它_不是_由某些顶级网络性能开发人员构建的,底部只有一个脚本。

开发人员多年来一直在建设网站。
网站所有者最关心设计和功能,因此开发人员将时间花在这些上。

改变工作方式、构建系统、代码……它必须很容易,非常容易,否则就不会发生。

我在许多网站上工作过,将 HEAD 中的 JS 组合成一个文件并将其加载到 BODY 的底部破坏了网站上的页面。 然后什么? 在大多数情况下,解决这个问题不仅仅是一个小时的工作。 需要进行认真的重构……而这不会发生,因为缺乏知识,尤其是缺乏时间。

(哦对了,线程被关闭了......)

我们正在谈论构建在 jQuery 和 Modernizr 之上的库。 都说了,真的。 谁用那个? 哦,该死,我忘记了 Twitter.com,它使用了两个 jQuery,并且在源代码中还有以下内容:

第 352 行,第 6 列:看到结束标记 div,但有开放元素。
错误行 350,第 6 列:未闭合元素 ul。
错误行 330,第 6 列:未封闭元素 ul。

期望浏览器纠错的问题是 HTML4 没有定义纠错机制,所以你最终会得到一个谁知道谁知道在哪里。 当然,HTML5 定义了错误处理,但它没有追溯力——仍然有很多“旧”浏览器存在。

说到废话,这里有人看过 jQuery ES5 垫片吗?

顺便说一句,您有什么要补充的吗?“使用 h5bp 的 webdev 实际上将拥有干净的 HTML,”

@GarrettS好吧,好吧,我应该写“将_可能_有干净的 HTML”

:-D 我们总是希望!

打败一匹死马,我知道......但事实证明,在我们进行这个令人兴奋的讨论的同时,当前版本的 LABjs 实际上有一个错误,导致 JavaScript 在某些浏览器中以错误的顺序执行: https: //github.com/getify/LABjs/issues/36

哦,讽刺的是。

必须。 抵抗。 发帖。 完全。 [不当。 图片。 为了。 以前的。 声明……哎呀! 痛苦!

我最喜欢的部分是当dhtmlkitchen.com (目前完全一团糟)开始谈论标记错误时。

该站点已转移到 Paulo Fragomeni。 是的,我做到了,并为我在那里写的东西感到自豪,就像这里一样。 去截一张你虚弱的头像吧,蠢货。

...在你做完之后,试着把你的脑袋从你的屁股里拿出来,了解我的旧个人网站(不再由我维护)和一个由团队开发并由以下人员资助的网站之间的区别一家盈利的、价值数百万美元的公司(尽管 Twitter 可能价值数十亿美元)。

很高兴我们保持这种优雅,并且_关于主题_,伙计们。

jashkenas 在本次讨论的早期就获得了相关信息。

但随后出现了强烈反对。 不! 一定不是! 苏德斯说要做! 使用 defer 有一个糟糕的建议,而不是在它失败时关心它是如何失败的。

然后具有讽刺意味的是,突然间有人声称 h5bp 用户会正确地做事。 这非常具有讽刺意味,因为此评论是在其支持者的_after_评论之后发布的,这些支持者显然产生了无效标记并使用了大量第三方抽象层(以及糟糕的抽象层)。 在关于使用 defer 的评论之后。

那么这与 dhtmlkitchen.com 关闭有什么关系呢? 什么都没有,很明显。 这只是来自无法忍受批评的 h5bp 分叉者的微弱抨击。

兄弟们
伙计。
兄弟们

此线程已关闭。 记住? 你不必回家,但你不能在这里发火。

嘿,你们都记得有一次我们制作了一个史诗般的线程,其中有多次辩论、个人火焰战争、人们到处发怒、一两个淫秽图像,以及全方位的美好时光? 不敢相信它是免费的。 我们应该在某个时候再做一次。

此页面是否有帮助?
0 / 5 - 0 等级