打造更轻量的 jQuery

发布日期: 作者:

jQuery 现在已经超过五岁了!在这段时间里,它随着它所服务 的浏览器、网站、设备、开发人员和用户一起发展。它也,嗯,增长了不少。jQuery 添加了许多有用的功能,但也积累了一些我们不希望永远支持的废弃代码。在台式机上使用高速连接可能不是问题,但我们希望 jQuery 也是移动设备的良好解决方案。

除了我们持续推动更高性能之外,我们未来版本的优先事项是减小压缩后的文件大小。当每个新功能或错误修复也必须保留所有现有功能和行为时,这很难做到。因此,今天我们想开始一个关于通过弃用一些功能来精简 jQuery API 的对话。以下是我们的弃用准则

  • 我们认为该功能不代表 jQuery 使用的当前最佳实践。
  • 该功能在实际使用中已被证明不受欢迎、令人困惑、效率低下或无效。
  • 增强该功能或解决其局限性不切实际或不可行。
  • 在将来某个时间将其移除可能会带来明显的可用性、大小或性能优势。

弃用只是您可以参与的过程中的第一步。我们的目标是

  • 解释弃用特定功能的原因,如上所述。
  • 在弃用和移除之间提供至少一个主要版本号,通常更多。
  • 为弃用功能提供替代方案,以便迁移不痛苦。
  • 倾听社区关于弃用和移除的反馈。

有时,就像 1.7 版本中的 event.layerX/layerY 那样,如果我们认为立即移除该功能比保留它更少痛苦,我们会提前发出通知进行重大变更。这些应该只是很少的例外情况。

1.7 版本的弃用

考虑到这些因素,我们认为以下功能从 1.7 版本开始被弃用。使用它们的现有代码仍然可以工作,但推荐的替代方案对于与未来版本的兼容性来说是更好的选择。

.live() 和 .die():我们仍然收到许多错误报告,并发现用户对 .live() 方法的怪癖感到困惑。现在在它的更新的 API 页面上记录了常见问题。我们强烈建议在新代码中使用 .on() 或 .delegate(),因为它们是更好的 API。考虑到它的广泛使用,我们不太可能在 1.8 中移除此 API,但请尽快更新您的代码。

非标准事件属性:作为我们提高事件处理程序性能的一部分,我们还弃用了将几个事件属性从原生事件对象复制到 jQuery 事件对象的操作,并将它们在 1.8 中移除:attrChange、attrName、relatedNode 和 srcElement。无需通过 event.NAME 访问它们,您可以通过 event.originalEvent.NAME 访问它们。

$.ajax() 延迟别名:在 1.5 版本中,我们在 jqXHR 对象上定义了 .error()/,success()/.complete() 作为延迟的 .fail()/.done()/.always() 方法的别名。虽然当时这似乎是个好主意,但它使 jqXHR 成为非标准延迟。这不是好事。尽可能使用延迟/承诺方法名称,而不是 jqXHR 名称。我们在这里还需要做一些工作才能提供完整的迁移路径,因此我们可能会在 1.8 之后继续支持这些别名。

deferred.isResolved() 和 deferred.isRejected():现在延迟和承诺有了进度通知和方便的 .state() 方法,我们弃用了这些旧方法,并将它们在 1.8 中移除。使用 N-1 个布尔方法获取 N 状态对象的 state 是一种残酷的代码版本,类似于“二十个问题”。基于延迟的代码很少需要检查 state,而现在返回的字符串对于调试场景来说更加方便,调试场景经常使用它。

.attr(“value”) 在输入上:为了向后兼容,我们一直在这里返回当前值(如“当前在输入框中的内容”),而不是真正的属性(HTML 中 value 属性所说的内容)。这让我们无法提供真正的属性值,并且令人困惑,因为 W3C 选择器作用于属性,而不是当前值。因此,我们弃用了此行为,并将它在 1.8 中移除。始终使用 .val() 方法来获取输入元素的当前实时值。在我们能够收回属性之前,您可以使用 $("selector")[0].getAttribute("value"),除了在 IE 6/7 中,它仍然会返回当前值。(我们的 1.8 解决方案将在所有浏览器上获取属性值,这也是我们急于改变此行为的另一个原因。)

.closest(Array) 返回 Array:此签名有点奇怪,它是为旧的实时事件代码创建的,但它返回的是 Array,而不是 jQuery 对象。从 1.8 开始,我们计划移除它。.closest() 的其他签名将保留,不受影响。

.data(“events”):jQuery 将其与事件相关的数据存储在一个名为(等待它)events 的数据对象中,该对象位于每个元素上。这是一个内部数据结构,因此在 1.8 中,它将从用户数据名称空间中移除,因此不会与同名的项目冲突。jQuery 的事件数据仍然可以通过 jQuery._data(element, "events") 访问,但请注意,这是一个未记录的内部数据结构,不应修改。

$.sub() 作为插件:虽然 $.sub() 对于创建插件的无干扰区域很有用,但它不属于 jQuery 核心,也不被其他代码广泛使用,因此我们打算在 1.8 版本中将其转换为插件以节省空间。

展望 jQuery 1.8

鉴于我们对精简 jQuery 的推动,1.8 中新功能的过滤标准将十分严格。即使是与性能相关的提案也需要权衡它们使用或节省的空间。可以通过插件、特殊事件、属性钩子或其他 jQuery 扩展机制实现的功能,目前可能仍会保留在核心之外。

这就引出了一个问题,我们可以在 1.8 中弃用什么,并最终将其移除以简化和简化库。这些东西不必完全消失;例如,它们可以移到一个单独的插件中,并且只有在需要时才包含。看看您如何使用 jQuery,并与您的同事讨论一下。

在几周内,我们将发布另一篇博文,征求您关于 jQuery 1.8 的想法——所以现在就开始思考吧!

编辑:不,我们还没有移除 IE6 支持,我们也无法移除。正如 John Resig 在每次 jQuery 大会上提到的那样,IE6 的大多数罪孽也降临在 IE7 和 IE8 上,它们加起来仍然占有超过三分之一的台式机浏览器市场份额。在我们可以同时淘汰 IE7 和 IE8 之前,移除对 IE6 的支持没有意义。

关于“打造更轻量的 jQuery”的 113 条评论

  1. 发布一个“精简”版本的 Jquery,然后发布一个支持所有内容的“完整”版本。您现在不应该放弃对这些浏览器的支持。您不知道谁会需要它。

  2. 我认为您应该大幅减少动画支持,并且在核心只提供基本的淡入淡出功能。

    您确实有 jQueryUI,它就是为这些事情而设计的。

  3. @Daniel

    您是否尝试过编译自己的 jQuery 版本,并选择您想要使用的部分?我敢打赌,这并不像您说的那样容易,因为模块在其他模块中是自由共享的。

  4. Brian Adams 说:

    很高兴看到 live()/die() 被弃用,但我希望看到 bind() 和 delegate() 也被弃用(可能甚至弃用 bind 快捷方法)。将事件处理整合到一组强大的方法中具有巨大的价值——特别是对于非程序员和刚接触该库的用户。

  5. 有人在使用这个“radio, checkbox, file, password, submit, image, reset, button”的过滤器吗?我甚至不知道,它能用,因为我一直使用 input[type=”checkbox”]。

  6. 我非常希望能将 jquery 分成两个部分,一个不涉及 DOM,只包含与对象相关的函数,另一个包含与 DOM 相关的函数。

    不涉及 DOM 的部分对于我们使用 Web Workers 来说至关重要。随着 Web Workers 应用的不断增多,操作对象的工具似乎越来越重要。

  7. jquery.html5.js 版本怎么样?更小的子集,以及新的 html5/css3/javascript 引擎支持和 GPU 加速。jquery.html5.js 适用于新浏览器:IE 10+、Firefox 9+、Google Chrome 17+、Opera 12+,而 jquery.html4.js 则为旧浏览器提供相同的函数。也许 jquery.compatibility.js 可以用于旧的和已弃用的函数。

  8. 虽然早期版本的 jQuery 最重视向后兼容性,但我们现在看到了一种趋势,即在最新的版本中打破这种兼容性,甚至开始删除向后兼容的“旧的糟糕的东西”。虽然精简代码是件好事,但在包含许多“模块”需要一起运行的框架中,例如 Drupal 或 Community Builder,这会带来很大的麻烦。

    因此,我建议采取以下措施(我没有看到有人在上面提出过,希望我没有遗漏):

    1)将 jQuery 精简到针对给定版本理想的 API,不提供任何向后兼容性支持。

    2)为该版本添加一个 jQuery-compatibility 插件,该插件可以恢复对需要向后兼容性的站点的支持,并在其中添加一个调试工具,该工具可以列出需要修复的向后兼容性问题,以帮助改进其他插件和 jQuery 使用的 API。

    这样,您就可以获得一个精简的现代 jQuery,并且不会失去 jQuery 的广泛使用,也不会在我们的框架中尝试使旧的和新的扩展能够顺利使用 jQuery 时遇到麻烦。

    您对这个提议有什么看法?

  9. 为了真正快速地进行,并摆脱所有这些冗余,以及许多网站不需要的那些未使用的功能,我建议

    短期
    1)在您的构建中将项目标记为已过时
    * 然后,您可以生成一个“兼容”版本和一个“精简”版本
    * 每个人都满意

    长期
    1)做 jQueryUI/Modernizr 正在做的事情
    * 启动那个自定义构建页面,让用户选择他们需要的功能!
    * 每个人都非常满意

    对我来说,这些是满足几乎所有需求所需的唯一东西。

  10. 不要删除 $.browser,因为它有时仍然是修复浏览器错误所必需的。并非所有事情都可以通过功能检测来完成。

  11. @Beat

    我喜欢兼容性插件或“jQuery legacy 插件”的想法。所有当前和未来已弃用的东西都可以放到其中。

    这样,如果您真的想要一个轻量级的 jQuery 文件,您就有足够的时间将您的代码更新到最新的 API。

  12. 对 IE6 的支持必须持续到我们能够放弃对 IE7 和 IE8 的支持为止。

    将 jQuery 分成类似于 jQuery UI 的模块毫无意义。如果您想要一个残缺的 jQuery 版本,请使用 jSlim 等外部项目来删除您不使用的部分,或者完全使用另一个库。实际上,使用您自己精简的 jQuery 版本比使用 CDN 中的版本效率更低,因为 CDN 中的版本很有可能在用户访问您的网站之前就被缓存。

  13. 为什么我们不将 jquery 代码分成浏览器特定的版本,每个版本都更小,执行速度更快。在加载网站时,应检查浏览器,并加载相应的库。

    此外,我不太熟悉和了解我不使用的函数。我们不应该扫描/投票,看看我们最常用的函数,即我们最想要的函数吗?

    此外,我支持一些强大的核心函数,并将快捷方式放到一个单独的库中。例如
    – 保留 toggleClass;插件用于 AddClass/removeClass
    – 保留 SlideToggle;插件用于 SlideDown/SlideUp
    – 保留 FadeToggle;插件用于 FadeIn/FadeOut
    – 保留 $.ajax;插件用于 $.put、$.get
    – 保留 .is();删除 .hasClass()

  14. @Kevin

    我们不再通过 CDN 使用 jQuery,因为每隔一段时间它就会变得无响应。

    至少 Google 在几个月前出现了这些问题,对于拥有 800 万独立访客/月的网站来说,这是不可接受的。因此,现在我们只是将它预先缓存到我们自己的服务器上,在其上加上一个长时间的到期标头,如果它仍然出现故障,至少我们知道是谁的责任 :)

    虽然我们可能会很快切换回更类似于以下内容的东西
    https://css-tricks.cn/snippets/jquery/fallback-for-cdn-hosted-jquery/

  15. Eli Perelman 写道

    > jQuery 普及的原因之一是它可以从 CDN 访问,并由于其缓存包含而提高网站性能。

    这是非常贴切的,但我不知道是否有办法让两方都满意?我可能只包含 CDN 版本,该版本往往非常快,因为每个人都将其缓存,但我可以理解,如果您要自己托管它,那么您可能希望进行模块化。我们能否只是将所有模块都放到 CDN 中,然后在下载时让用户选择模块?

  16. 感谢您没有删除对 ie6 的支持!对于我们的企业业务来说,您必须支持它至关重要。我真的不知道如果你们不支持我会怎么办,我认为没有其他工具包足够成熟可以在其中使用。如果那样的话,我可能会建议我们迁移到 Java swing。

  17. 我同意 T.J. Crowder 的观点。

    我在 BT(英国电信)工作,这是一家领先的公司。
    我们公司目前还没有准备好放弃 Internet Explorer。
    目前,我们电脑上唯一允许的 IE 版本是 IE6 和 IE7。仅出于“安全原因”。
    所有新应用程序都必须保证能够在这些版本上运行。
    短期内这种情况不太可能改变……让许多人感到遗憾。

    因此,考虑到情况可能有一天会改变,我将所有开发都与其他所有浏览器兼容,并仍然希望有一天 IE 会被禁止,因为它不符合 W3C 的建议。

  18. 33,285 字节(32.50 KB)在 gzip 压缩和缩小之后并不算大……我曾在某处读到 iPhone 以前会缓存 25kb 的文件,但现在大约是 4mb?

    因此考虑到这一点……我对 jQuery 的大小并不太在意,还有更重要的事情需要担心。当您的网站包含许多大型促销项目时,这些项目本身就大约有 60-100kb,而且它们不像 jQuery 那样来自访问其他网站时已经缓存。
    我目前将所有内容都打包在 head.js 中,但我认为在这种情况下,我应该利用用户已经缓存的 jQuery。在我的包中下载另一个 32kb 与另一个异步请求(如果它没有被缓存)相比……

    我的包文件在缩小/gzip 压缩之后大约有 100kb,其中所有内容都是模块化的,例如图像滑块、轮播、网站特定内容……也许我可以替换 jQuery UI 中的可拖动、可放置、可滑动等许多核心功能。

  19. 将 jQuery 进一步模块化,它应该更像 jQuery UI。

    您仍然可以保留标准的 GOD 对象版本,但我认为如果用户可以选择他们想要/不需要的部分,以减少他们传递给用户的代码量,这将非常有益。

  20. John Farrar 说:

    删除 .error()/,success()/.complete() 方法可能会节省空间,但也意味着我们将这些函数重新迁移回编写更多代码,而不是 jQuery 那种用更少代码做更多事情的方式。在我看来,这似乎是朝着错误的方向发展,但理解我们正在寻找所有可能的方法来使代码更加面向移动设备。

    移动设备的功能快速增加。看看这一切最终会发展成什么样子会很有意思。特别是现在 “Flash” 正在被抛弃。我们将(jQuery 社区)有机会填补那些急于寻找可持续解决方案的人的空白。

    所以我们有 jQuery Mobile,jQuery 都是针对移动设备的考虑因素。jQuery UI 会是移动设备的考虑因素吗?什么时候适用或者它是否适用?看来,那些可能已经研究过这个问题的人可以提出一些指南和/或单元测试。如果他们做到了,这对社区将有很大帮助!(超出了我的能力范围,或者我很乐意这样做)。

  21. 我认为 $(…).live() 还没有好的替代方案。例如,您如何转换以下代码段?

    $(‘my-long-selector-here’)
    .live(‘click’, onClick)
    .live(‘change’, onChange)

    据我所知,您认为我们应该这样写吗?

    var s = ‘my-long-selector’
    $(document).on(‘click’, s, onClick)
    $(document).on(‘change’, s, onChange)

    真的吗?!

  22. 我投票放弃 IE6 支持。这将成为一个转折点。jQuery 库是 web 开发中最流行的库,它有能力推动行业朝着创新方向发展。

  23. 同意,将 IE6 支持作为一个外部库会很好,就像 jQuery UI 从核心库中分离出来一样。

    这肯定会让许多人的 jQuery 变得更小。

  24. 在将内容拆分成单独的模块之前,请考虑带宽/延迟。缩小/gzip 压缩后的版本已经增长了三倍。在同一时期,我的带宽增长了十二倍。将内容拆分可能会节省 2k 或 3k 的大小,但最终可能会在总体网络时间方面付出更多代价。无论如何,使用 CDN 版本……大小目前不是什么大问题。

  25. Effects API 在 jQuery 1.7 中从第 8273 行到第 8903 行。
    16 kB 未缩小 = 6,7 kB 缩小(节省),3,2 kB 缩小+gzip 压缩(节省)=> jquery-1.7.min.js.gz 小了 10%(29,2 kB)。

  26. 如果您想删除 API 的一部分,请务必这样做,但将其作为 jQuery 2 的开端,并将 1.x 分支保持原样。如果 1.x 分支中的下一个版本不再具有在书籍和网络上的教程等中记录的功能或行为,这将让开发人员非常困惑。

    我的建议是:现在开始一个分支并将其命名为 jQuery 2,发布一些预览版本等,并在网站上创建一个单独的页面。将 1.x 保持原样,并继续添加新功能和发布补丁。

    这样,版本号将符合语义化版本控制 - http://semver.org/,大多数开发人员都熟悉它(即使他们可能不知道它叫什么)。

    将 Python 2 -> Python 3 作为很好的例子,您可以在其中进行非向后兼容的版本发布,但也可以将新功能移植到旧分支中并维护它。

  27. 减小 API 大小的一种方法是弃用并删除大量的方法别名。

    * 所有事件简写形式都由 .on/.trigger 重复。
    * 所有各种 .ajax 别名,例如 .get() 和 .post(),都是 .ajax() 的有限/不一致的重复。
    * hasClass 重复 .is()。

    使用更少的方法来完成相同的事情是帮助减少 jQuery 在网络上传输大小的一种方法。但弃用/删除功能应在 2.x 版本中进行。在没有版本升级的情况下进行重大更改会导致升级混乱。

  28. 很好的举措,尽管我认为当前的文件大小不是问题。

    但是,目前删除 IE6 支持将是一个重大打击。

  29. 请在 API 中添加关于所有弃用功能的说明!大多数人不会阅读博客,他们只会在 API 中查找内容。感谢您的辛勤工作!

  30. Dannyyyyyy 说:

    我将 1.6 分成了两个 14kb 的 JS 文件,效果很好。

    我该怎么做呢?

    很简单。

    jq.js - 包含字符串,例如 asd = ‘jQuery.extend=jQuery.fn.extend=function(){v….

    然后在

    realq.js - 中

    // [[Class]] -> type 对
    class2type = {};
    eval(asd);

    使用 eval 将代码放入字符串中 :)

    我认为,请不要只是精简,而是将代码分离成两个大约 14kb 的文件。

  31. 我最近在 DC jQuery 会议上做了一个关于如何避免使用 jQuery 的全部功能的演讲。例如,我谈到如何使用 Sizzle 通过 CSS 选择器获取 DOM 元素数组,如果您不需要 jQuery 特定的功能,并且不介意编写老式数组循环的麻烦。因此,我一直都在考虑在没有加载 jQuery 时使用 Sizzle(),而在加载 jQuery 时使用 $.fn.find()。

    由于 jQuery 和 Sizzle 的团队成员相同,并且 Sizzle 已经可以外部使用(自包含),因此在早期模块化这方面是很有意义的。建议:

    (1) 创建 Sizzle 的压缩版本,并将其放在 jquery-sizzle-version-xxx.zip 文件中。(我使用 YUI 压缩器为我自己压缩了它,但其他人也需要压缩版本。)

    (2) 为 Sizzle 添加 AMD API 支持。

    未压缩的压缩版 Sizzle 大小是未压缩的压缩版 jQuery 的 1/6,因此我们谈论的是已经模块化的相当多的代码。

  32. 这里适用 TL;DR。
    不过,我确实阅读了大量的讨论,我喜欢创建 2.0 版本的想法,它不再支持旧版浏览器,而不仅仅是 IE。我认为没有理由不做这件事。需要支持旧版浏览器和任何已弃用功能的开发人员,只需使用 2.0 之前的版本。就这样,搞定了。然后我们就可以继续前进。
    仅供参考。

  33. 我注意到 jQuery 1.7 与 1.6 相比有一个有趣的行为,也许有人可以帮我识别它是一个错误还是弃用的一部分?

    以下代码片段选中一个复选框,然后取消选中它(别在意选择器,它只是示例)

    $(‘input[type=checkbox]’).attr(‘checked’, ‘checked’);
    $(‘input[type=checkbox]’).attr(‘checked’, ”);

    在 1.7 中,第二行代码不起作用。它不会销毁属性,而是将其值设置为“”。因此它仍然被选中。

    当然,编写这段代码的正确方法可能是 .removeAttr(‘checked’),但是为什么之前提到的代码片段不再起作用了?

  34. 很高兴听到 jQuery 将会精简的消息。

    完全同意 Alistair 和其他人的观点,$.browser 可以删除。正如文档中所说,最好使用特性检测。

    在您别无选择,只能使用浏览器嗅探的情况下,我认为最好从服务器端的标头执行操作,并在 html 元素上添加 data- 属性。这样更简洁。

  35. 我同意,如果要大幅更改 API,就将其称为 2.0。这意味着开始新项目的人可以获取最新版本,永远不必担心向后兼容性。

    我喜欢模块化的想法(就像前面提到的海报一样,我在每个项目中都不会使用 jQuery 的所有功能)。将第一个模块设为 jQuery 1.x 迁移模块。让 jQuery 2.0 内核变得精简高效,适用于移动设备。

    关于“不要担心文件大小,只需使用 CDN”的论点在桌面端是可行的,但在移动端却行不通。缓存通常会更频繁地清除。并且可以缓存的总大小更小。jQuery 通常会超过这个限制,无法被缓存。

    关于模块化导致多个网络连接的反对意见是荒谬的,因为人们总是可以选择将较小的脚本文件连接在一起。

  36. 我认为 jQuery 2 应该

    1. 只支持 HTML5/CSS3/JS1.9
    2. 为我们可怜的 IE 用户推荐 ChromeFrame(是时候说,IE10 或再见 IE,这样我们才能真正创新)
    3. 使用 AMD 来支持模块化

    我现在正在为我们的企业客户推荐以上 3 点,我认为以其当前形式的 jQuery 在这种环境下将变得越来越不相关。

  37. 我以前使用 jQuery 是因为它体积小,而且功能很实用。后来它变成了我服务器上最大的文件(除了提供的可下载 ZIP 文件),所以我开始越来越少地使用 jQuery。

    为什么不按照“modernizer”的方式做呢?给我们提供一组复选框,让我们选择自己——用户/设计师/开发者——想要和需要什么。不多不少。

    或者,将上面我同意的多个评论用更戏剧性、更简洁的一句话概括:“模块化或死亡”。

  38. 将其命名为 2.0。
    将 IE6 设为插件。
    将 IE7 设为插件。
    将 XML / XPath 设为插件。
    只有在没有原生 querySelectorAll 的情况下才加载 Sizzle(不容易做到,但我觉得值得)
    精简内核,并使更多功能成为“可插拔”的。

  39. 很高兴听到 jQuery 将会支持手机网页浏览器。当然,最好弃用旧版 jQuery 中未使用的函数,这样 jQuery 会变得更小,效率更高。我对 jQuery 致以最诚挚的敬意。

  40. 对于某些任务,我想要的只是拥有 Zepto.js 的 API(函数选择)但兼容 IE 的版本。我一直都在考虑自己做一个,但我不想每次想要继承 jQuery 的改进时都必须重构自己的工作。它需要一个完整的模块化系统吗?我认为不需要。

    关于 live/bind/click 等,我同意我们只需要 on/off。另一方面,这些大多数现在只是别名,大约占用 10 行代码。去掉它们不会带来明显的瘦身效果。

    有人建议移除 .each(),必须承认 .each() 是你能使用的效率最低的迭代器。但当“慢 5 倍”仍然只有几毫秒时,我不介意这种便利。我不希望看到 .each() 消失。

  41. 将 IE6 支持放到插件中,如果你需要它,只需添加插件,它就能像以前一样工作……IE 应该从地球上消失,因为他们不断地给自己身上涂抹呕吐物。IE 令人作呕。