【CSDN编者按】7月17日,GitHub改版并放弃了jQuery, 这对于GitHub来说,绝对是一件可以载入公司史册的大事。

今天的文章中,四位参与改版和弃用JQuery的GitHub工程师,将介绍最初GitHub使用jQuery的历史背景、和后来不再需要jQuery的原因,并讲解GitHub如何在不引入其他库、或框架的情况下,通过标准浏览器API,来实现他们需要的功能的。

为什么最初需要jQuery

我们最近刚刚完成了一个里程碑,成功地从GitHub.com的前端代码的依赖中去掉了jQuery。这标志着这项一点一滴持续了多年的jQuery解耦合工作的完成,以及我们终于可以完全删除这个库了。

GitHub.com在2007年末引入了jQuery 1.2.1作为依赖。当时距离Google发布Chrome浏览器的第一版,还有一年的时间。

当时没有什么标准的方法,通过CSS选择器,来查询DOM元素,也没有标准的方式,来实现元素的视觉动画,而由Internet Explorer倡导的XMLHttpRequest接口,也像许多其他API一样,在各种浏览器上的实现不一致。

而jQuery使得操作DOM、定义动画和实现“AJAX”请求,变得十分简单。简单来说,它使得Web开发者可以创建更现代、更动态的效果。

最重要的是,通过jQuery在一种浏览器上实现的功能,基本上也能在其他浏览器上运行。

在GitHub的早期,许多功能才刚刚起步,有了jQuery,我们的小团队才能迅速地建立原型、并推出新功能,而不需要为每种Web浏览器调整代码。

我们还把jQuery简单的接口,作为蓝图来构建扩展库,这些库(pjax, https://github.com/defunkt/jquery-pjax和Facebox,https://github.com/defunkt/facebox),后来成了GitHub.com前端的其他部分的组成部分。

我们会永远感谢John Resig和其他jQuery贡献者们,创建并维护了这个十分有用、并且在历史上十分重要的库。

后来的Web标准

多年以后,GitHub成长为拥有数百名工程师的公司,还逐渐组成了一个独立的团队,专门负责我们发送到浏览器上的JavaScript代码的尺寸和质量。

我们一直在监视技术债务,而有些技术债务的原因,是那些曾经有价值、但后来随着时间的发展而失去了价值的依赖。

而对于jQuery,我们将它与现代浏览器中迅速发展的Web标准做了比较,结果发现:

  • $(selector) 可以简单地用querySelectorAll()替换;

  • CSS类名切换,可以通过Element.classList实现;

  • CSS现在支持在样式表中定义视觉动画,无需使用JavaScript;

  • $.ajax请求可以用Fetch标准实现;

  • addEventListener()接口已经十分稳定,足以跨平台使用;

  • 我们可以用一个轻量级的库,来封装事件代理模式;

  • jQuery提供的一些语法糖,已随着JavaScript语言的发展,而变得多余。

而且,链式语法并不能满足我们直观地书写代码的需要。例如:

$('.js-widget')
  .addClass('is-loading')
  .show()

这种语法很容易编写,但以我们的标准来看,它并不能很好地传达作者的意图。作者希望页面上只有一个JS-Widget元素、还是有多个?

而且,如果我们修改网页代码时,一不小心删掉了JS-Widget类名,浏览器会产生异常并告诉我们发生了错误吗?

默认情况下,如果类名不匹配,jQuery会静默地忽略整个表达式,但在我们看来,这种行为与其说是功能,不如说是个Bug。

最后一点,我们想使用Flow(https://flow.org/)进行标注,从而在构建时实现静态类型检查。

但我们得出结论,链式语法并不能很好地适应静态分析,因为几乎所有jQuery的函数的返回值,都是同一种类型。

我们选择Flow、而不是其他库的原因是因为当时像@flow weak模式等特性可以让我们逐渐地、有效地给大量几乎没有任何类型的代码添加类型。

总的来说,jQuery解耦合,意味着我们可以更依赖于Web标准,将MDN Web文档,作为事实上的前端开发标准,方便以后维持代码的灵活性,并最终从打包文件中,去掉一个30KB的依赖,提高页面加载速度、和JavaScript的执行时间。

增量解耦合

即使确定了最终目标,我们也不能简单地,把所有资源都花在,使用原生JS重写jQuery的事情上。

一旦发生什么事情,这种急功近利,会导致许多网站功能倒退,从而不得不花更多时间去解决。我们必须要这样做:

设定好度量标准,跟踪jQuery调用次数和全部代码行数的比例,并随时监视该度量,保证它不变或减小,而不会增加。

我们不鼓励在任何新代码中使用jQuery。为了使用自动化减轻工作量,我们创建了eslint-plugin-jquery(https://github.com/dgraham/eslint-plugin-jquery#readme),如果任何人尝试使用jQuery功能(如$.ajax),它就会造成CI检查失败。

旧代码中有大量的ESLint规则违反,这些违反我们都使用eslint-disable规则在代码注释中标注出来了。这样就能尽快进行代码审查、并集思广益。

许多旧代码显式地耦合了Pjax和Facebox这两个jQuery插件的外部接口,因此我们在使用原生JS,替换这两者的实现时,尽力保持接口不变。静态检查让我们能更信心地进行重构。

许多就代码都与rails-behaviors(http://josh.github.io/rails-behaviors/)有接口,后者是我们在Ruby on Rails和JS之间的适配器。这种接口会为特定的表单,添加一个AJAX生命周期处理函数。

// LEGACY APPROACH
  $(document).on('ajaxSuccess', 'form.js-widget', function(event, xhr, settings, data) {
    // insert response data somewhere into the DOM
  })

为避免不得不用新方法,一次性重写整个网站,我们采用了触发伪“*AJAX*”生命周期事件的方式,使这些表单,能像以前一样继续异步提交内容,只不过内部使用的是fetch()。

我们定制了一个jQuery,一旦我们认为某个模块不再需要,就把它从定制版本中删掉,使jQuery更灵巧。

例如,在删除最后一个jQuery专用的CSS伪类(:visible、:CheckBox等),我们就删掉了Sizzle模块(https://sizzlejs.com/);在使用fetch()替换了最后一个$.ajax调用之后,就删掉了AJAX模块。

这样做有两个目的,一是加快JavaScript执行速度,一是确保新功能不会使用被删掉的功能。

根据网站访问分析的结果,只要有可能,我们就会删掉支持旧Internet Explorer版本的部分。当某个IE版本的使用率,降到某个阈值之下,我们就不会再为其提供JavaScript,从而得以专注于,支持更多现代浏览器。

提早去掉IE8~9的支持,使得我们可以使用更多的原生浏览器功能,不用再勉强进行Polyfill。

作为构建GitHub.com前端的新方法的一部分,我们尽可能采用基础的HTML来实现功能,只把JavaScript用作渐进式增强。

这样,即使Web表单和其他UI元素上使用了JS,它们也能在禁用了JavaScript的浏览器中运行。一些情况下,我们可以删掉整个旧有行为,不用再使用原生JS重写。

通过这些方法(以及多年来积累的其他方法),我们得以逐渐地减小对jQuery的依赖,直到没有一行代码使用它。

自定义元素

近几年人们谈论得最多的一项技术就是自定义元素,它是个浏览器原生的组件库,也就是说用户无需下载、解析或编译任何框架。

我们从2014年起,就根据v0规格,建立了一些自定义元素。但是,由于当时的Web标准依然不明确,所以我们并没有深入研究。

直到2017年,Web组件的v1规格发布,而且Chrome和Safari都开始支持,我们才开始在大范围内使用自定义元素。

在jQuery迁移过程中,我们寻找适合提取成自定义元素的部分。例如,我们将使用Facebox显示对话框的代码,改成了<Details-Dialog>元素。

渐进式增强的思想,也应用到了自定义元素中。就是说,我们尽可能保持标签的内容,仅在标签不能实现的地方,添加新的行为。

例如,<local-time>默认会显示原始的时间戳,然后增强翻译成本地时区内的时间;而<details-dialog>如果嵌入到<details>元素中,那么即使没有JavaScript,本身也是交互式的,但会利用提高可用性的功能进行增强。

下面是实现自定义元素<local-time>的例子。

// The local-time element displays time in the user's current timezone
// and locale.
//
// Example:
//   <local-time datetime="2018-09-06T08:22:49Z">Sep 6, 2018</local-time>
//
class LocalTimeElement extends HTMLElement {
  static get observedAttributes() {
    return ['datetime']
  }

attributeChangedCallback(attrName, oldValue, newValue) {
    if (attrName === 'datetime') {
      const date = new Date(newValue)
      this.textContent = date.toLocaleString()
    }
  }
}

if (!window.customElements.get('local-time')) {
  window.LocalTimeElement = LocalTimeElement
  window.customElements.define('local-time', LocalTimeElement)
}

我们在试图采用的Web组件功能之一,就是Shadow DOM。

Shadow DOM的强大功能,可以给Web带来许多可能性,但也使得它很难polyfill。

因为现在的polyfill方式,会给那些操纵与Web组件无关的DOM的代码,也造成大量性能损失,所以还不适合在生产环境中使用。

Polyfill

我们在转换成标准浏览器功能的过程中,使用了下面这些polyfill。我们尽量仅在绝对必须时——即需要兼容旧版本浏览器时——才使用polyfill。

  • github/eventlistener-polyfill;

  • github/fetch;

  • github/form-data-entries;

  • iamdustan/smoothscroll;

  • javan/details-element-polyfill;

  • jonathantneal/closest;

  • kumarharsh/custom-event-polyfill;

  • marvinhagemeister/request-idle-polyfill;

  • mathiasbynens/Array.from;

  • mathiasbynens/String.prototype.codePointAt;

  • mathiasbynens/String.prototype.endsWith;

  • mathiasbynens/String.prototype.startsWith;

  • medikoo/es6-symbol;

  • nicjansma/usertiming.js;

  • rubennorte/es6-object-assign;

  • stefanpenner/es6-promise;

  • webcomponents/template;

  • webcomponents/URL;

  • webcomponents/webcomponentsjs;

  • WebReflection/url-search-params;

  • yola/classlist-polyfill。

原文:https://githubengineering.com/removing-jquery-from-github-frontend/

作者:mislav, koddsson, muan, keithamus

译者:弯月,责编:胡巍巍

GitHub:为什么我们最终选择放弃了 jQuery相关推荐

  1. 外企九年-我最终选择放弃

    首先想说的是,我是一个平凡的在深圳打工的女人.在这里只是想通过我从毕业到现在9年的打工生活和与我类似经历的年轻人一起分享.在现在的经济危机时期,很多人都还在找工作,很多人还在庆幸自己可以保的住饭碗,但 ...

  2. 【转】[行业透视] 外企九年-我最终选择放弃

    昨晚失眠,早晨犯困,一边喝咖啡一边看学长分享的这篇文章.尽管之前经历不多, 但很多事情真的能引起我的一些感触.自己的人生规划清晰,再看这篇文章就觉得就会感 觉是一种启发,毕竟大家都在走自己的路!原文如 ...

  3. 外企九年,我最终选择放弃——送给和我一样纠结毕业是读研,国企,外企等等的人们

    外企九年,我最终选择放弃--送给和我一样纠结毕业是读研,国企,外企等等的人们 朱斯辰的日志 昨晚失眠,早晨犯困,一边喝咖啡一边看学长分享的这篇文章.尽管之前经历不多,  但很多事情真的能引起我的一些感 ...

  4. 【外企九年,我最终选择放弃】

    [外企九年,我最终选择放弃]--送给和我一样纠结毕业是读研,国企,外企等等的人们.[文章是转的,原帖楼主不清] 昨晚失眠,早晨犯困,一边喝咖啡一边看学长分享的这篇文章.尽管之前经历不多,  但很多事情 ...

  5. 外企9年,我最终选择放弃

    首先想说的是,我是一个平凡的在深圳打工的女人.在这里只是想通过我从毕业到现在9年 的打工生活和与我类似经历的年轻人一起分享.在现在的经济危机时期,很多人都还在找 工作,很多人还在庆幸自己可以保的住饭碗 ...

  6. 外企9年,我最终选择放弃 zz

    昨晚失眠,早晨犯困,一边喝咖啡一边看学长分享的这篇文章.尽管之前经历不多, 但很多事情真的能引起我的一些感触.自己的人生规划清晰,再看这篇文章就觉得就会感 觉是一种启发,毕竟大家都在走自己的路!原文如 ...

  7. 转载: 外企九年-我最终选择放弃

    很深的感悟 [@more@] 有点长,但是不会对不起你的时间. 首先想说的是,我是一个平凡的在深圳打工的女人.在这里只是想通过我从毕业到现在9年的打工生活和与我类似经历的年轻人一起分享.在现在的经济危 ...

  8. 外企九年-我最终选择放弃 1

     首先想说的是,我是一个平凡的在深圳打工的女人.在这里只是想通过我从毕业到现在9年的打工生活和与我类似经历的年轻人一起分享.在现在的经济危机时期,很多人都还在找工作,很多人还在庆幸自己可以保的住饭 ...

  9. (转)GitHub 被微软收购后的 52 天,改版并放弃了 jQuery!

    上个月,『全球最大同性交友平台』GitHub 被微软以 75 亿美元(折合人民币 480 亿)的价格正式收购,这一事件引发诸多程序员担忧: 微软收购之后,Github 是否会将不再开源? 为防范于未然 ...

最新文章

  1. R语言包_knitr
  2. webpack 开发模式管理 Development
  3. VC++网络资源集合
  4. [并发编程] - Executor框架#ThreadPoolExecutor源码解读01
  5. ConcurrentModificationException并发修改异常
  6. 商业软件中常见的修饰词
  7. 量子计算机设计理念和思路,课程的设计理念与思路
  8. 操作系统上机作业--多线程排序
  9. LINK : fatal error LNK1104: 无法打开文件“LIBCD.lib”
  10. Task类的简单介绍
  11. java 时间转为毫秒数_疫情期间面试总结一(java基础方面)
  12. ChipGenius-U盘加密狗检测工具
  13. C语言什么是时间序列,什么是横截面数据、时间序列数据和面板数据
  14. oracle 如何修改表空间,ORACLE修改表空间方法
  15. INTERCEPTOR DISCONNECTED 的问题
  16. 组合数学(二)排列数和组合数
  17. python基础03/字典
  18. 防洪决策指挥系统(Axure高保真原型)
  19. 用计算机算一算循环小数,循环小数化分数计算器
  20. SpringBoot详解

热门文章

  1. leetcode python3 简单题172. Factorial Trailing Zeroes
  2. python快速编程入门课本中的名片管理器_python优雅操作-实现名片管理系统
  3. 【图像处理】MATLAB:图像分割
  4. C++11 多线程 线程管理基础
  5. java仓库管理设计报告_基于JAVA的仓库管理系统设计毕业设计.doc
  6. 【js】【前台输入效验】【validate插件的使用】 前端
  7. EXCEL数据有效性—单元格筛选的改进
  8. VBA中使用EXCEL工作表函数
  9. 时隔六年,FreeDOS终于更新,是否还能与Windows一战?
  10. 从“智能湖仓”升级看数据平台架构未来方向