• 关于脚本载入器的思考


    最近看了一些脚本载入器的文章,包括很火的LABjs,controlJS,还有淘宝玉伯的seajs,很火的话题,也比较有争议!下面转一篇尼古拉斯的文章,我也同意作者的观点,希望很能够得到浏览器原生的支持!

    第一篇日志的评论中有来自 Kyle Simpson 的批评 (Kyle 是另一个脚本载入器 LABjs 的创建者)。LABjs 目标和 ControlJS 有些不同:开启 JavaScript 文件的平行下载,同时管理执行顺序。为了要做到这点,LABjs 需要知道哪些浏览器支持平行下载,然后为不支持的浏览器提供其他解决方案。

    然而,LABjs 和 ControlJS 都有个问题:他们用了多种浏览器探测技术来决定如何脚本载入的方式。有些人觉得 LABjs 用的浏览器接口(探测)比 ControlJS 的 user-agent 探测安全点,我不同意。浏览器接口(探测)其实是特征探测加假设,天生就有缺陷()。浏览器接口(探测)不比 user-agent 探测准确,也并非更稳定。我没有说 user-agent 探测是个好东西,但至少他明确地知道要探测什么。我总是选择清晰的而非含糊的,因为这可以让我们减少错误,或者当错误发生时,可以更快地定位。这个讨论有 点偏离本文的主题了。

    LABjs 其实已经证明了,“为不同浏览器使用不同的脚本加载技术”不是个好办法。他在面对浏览器的突然更新时不堪一击,所以我不建议使用尝试征服浏览器的脚本载入 器。Kyle 曾由于 Firefox 4 每夜版更新后破坏了 LABjs 的实现,。这个问题是:Firefox 4 动态插入脚本元素不再保持执行顺序,而这正式 LABjs 的实现所依赖的。这个变更使 Firefox 和 HTML5 规范及其他浏览器保持一致。毫无疑问,面对浏览器的高速发展,ControlJS 也将会面临同样的问题。对应解决方案的维护成本就变得很高。

    真正的问题

    有些人在讨论 LABjs 和 ControlJS 尝试解决的真正问题。事实上,他们面临着三个问题。

    第一,两者都尝试实现 JavaScript 的平行下载。这很有意义,但很多新的浏览器了。虽然可以通过变通的方式让老浏览器也实现 JavaScript 的平行下载,在学术上很有价值,但我不认为值得去做。浏览器正在为我们解决这个问题,脚本载入器不要做了。

    第二,LABjs 专注于保持脚本执行的顺序。我们要先假设:你希望下载多个 JavaScript 文件,且他们之间有依赖关系。我并不推荐这样做,但其他有些人觉得这很重要。ControlJS 并不关心这个。但不管怎样,这是个没有被浏览器合理解决的问题,如果你要用他,就必须用脚本载入器。

    第三,ControlJS 非常关注 JavaScript 下载和执行的分离。为实现这个想法,需要可以下载 JavaScript 文件但不执行他,直到想执行时再执行。这是个很有趣的概念,且在社区里做了很多实现(Steve 在他的博文中提到)。但这需假设你的页面是渐进增强的,比如并不一定要有 JavaScript 。LABjs 没有处理这个问题,浏览器也没有。

    战斗的号角

    尽管 Kyle 和我在很多事情上都有不同的看法,但他对问题 #2 通用解决方案的呼吁我非常认同:我们需要的不是脚本载入器,而是实现所有开发者处理 JavaScript 文件所需要的原生方法。脚本载入器展示了解决性能问题的一些方法,下一步应该由浏览器开发商来实现。Kyle 整理了问题 #2 相关一些 (注意:问题 #3 还没有提案)。当时 Kyle 也问了我对此的看法,但我被一些项目绊住,直到现在也没时间去深入研究。

    async=false?

    Kyle 的提案里有关于 script 标签 async 属性的增强,有点奇怪。async 属性是个布尔值属性,意味着只要他出现就开启这个功能,所以下面三行是等价的:

    < async src="foo.js">
    < async="true" src="foo.js">
    < async="false" src="foo.js">
    这和 HTML5 规范表现一致:马上开始下载且在下载完成时立即执行,不考虑原来的顺序。你可以在 JavaScript 中通过设置 script 元素的 async 属性来开启或关闭这个特细功能:

    var script = document.screateElement(“script”);
    script.async = true; // enable async per HTML
    Kyle 的提案中还提到,在 JavaScript 中设置 script 元素的 async 属性会触发新的模式。所以下面这行代码的意义就变了:

    var script = document.screateElement(“script”);
    script.async = false; // switch into new mode (WebKit nightly, Firefox 4)
    以前,设置 async 为 false 没什么效果。而现在,在支持他的浏览器里设置 async 为 false 会让脚本通过非阻塞的方式下载且保持执行顺序不变。

    当我为 Kyle 推送提案的坚持鼓掌时,也感到了一些不妥。对于我来说,这行代码读起来是 “此脚本非异步”,而不是 “此脚本是异步的,但需要保持执行顺序”。多说一边,我喜欢清晰的而非含糊的,这可以帮助我们避免错误。

    他的 twiki 里还提到另一个备选提案,创建 scriptgroup 元素从逻辑上让脚本文件捆在一起:

    < src="foo.js">
    < src="bar.js">
    <>
    somethingInline();

    我非常喜欢这个提案。非常清晰,对他能做什么没有任何疑问,且可以添加事件处理器到 元素,监听全部文件下载完成。虽然引入了一个新元素,但为了思路上的清晰,我想这个开销会被开发者接受的。

    分离下载和执行

    分离 JavaScript 的下载和执行非常必要,但目前还没有一个非常好的方案。不仅仅是针对页面载入时初始脚本,还有页面载入完成后动态地插入的脚本。在我的演讲 《Performance on the YAHOO! Homepage》中,我介绍了页面载入后如何缓缓执行 JavaScript ,而不影响用户进行其他操作。预载入 JavaScript 而不执行的的能力正变得越来越重要,而这正是 ControlJS 尝试解决的。

    理想的情况下,我期望能这样写:

    var script = document.createElement(“script”);
    script.type = “text/cache”;
    script.src = “foo.js”;
    script.onload = function(){
    //script has been loaded but not executed
    };
    document.body.insertBefore(script, document.body.firstChild);

    //at some point later
    script.execute();
    这已经是我所有想要的了,不想先发请求去下载一个文件,然后再发另一个请求并期望他在缓存里 —— 这是非常不可靠的解决方案。我所想要的是下载一个文件,就让他待在缓存里,然后只要调一个方法就可以执行代码。而这正是 ControlJS 的模型。

    最后

    LABjs 和 ControlJS 都在尝试解决 JavaScript 载入的问题,方法略有不同。Kyle 和 Steve 都非常聪明,研究了不同的方案来解决类似的问题。好消息是现在我们有两个脚本载入器,他们展示了开发者尝试在页面里载入脚本的不同方法,并希望浏览器开发 商能实现原生的解决方案,这样在不远的将来就再不需要脚本载入器了。

    而短期来说,Kyle 和 Steve 两位,非常抱歉,两者我都不推荐使用。两个类库都展示了脚本载入不同的有趣的方式,但依赖于浏览器探测就意味着需要不停监控,且当浏览器更新时跟进更新。 对于大型的 web 应用来说可维护性非常重要,而两个类库看似都增加了额外的维护开销。

  • 相关阅读:
    宿主机( win 7 系统) ping 虚拟机VMware( cent os 6.6 ) 出现“请求超时”或者“无法访问目标主机”的解决方法
    Java实现 LeetCode 23 合并K个排序链表
    Java实现 LeetCode 23 合并K个排序链表
    Java实现 LeetCode 23 合并K个排序链表
    Java实现 LeetCode 22 括号生成
    Java实现 LeetCode 22 括号生成
    Java实现 LeetCode 22 括号生成
    Java实现 LeetCode 21 合并两个有序链表
    Java实现 LeetCode 21 合并两个有序链表
    Java实现 LeetCode 21 合并两个有序链表
  • 原文地址:https://www.cnblogs.com/shihao/p/2182845.html
Copyright © 2020-2023  润新知