JavaScript 进阶营程序员javascript

Github.com 前端弃用 jQuery 始末

2018-10-12  本文已影响20人  1024译站

1024 译站按:早在今年7月份,Github 一名员工发布了一条 Twitter, 大意是 Github 网站前端决定放弃使用 jQuery,改用原生 JavaScript。一时间在前端业界引起了不少讨论,那么究竟是什么原因让 Github 决定放弃了使用多年的 jQuery 呢? 这篇文章会给出答案。

最近我们完成了一个里程碑:我们把 jQuery 依赖从 Github.com 前端代码中移除了。实施多年的渐进式解耦 jQuery,直至我们能够完全移除它,现在画上了句号。在这篇文章中,我们会解释一下我们是如何开始依赖 jQuery 的,我们又是如何意识到不再需要它的,以及指出我们如何做到使用标准浏览器 API 完成所有事情,而不是换成另一个库或框架。

为什么早期需要 jQuery

GitHub.com 在2007年末将 jQuery 1.2.1 作为依赖项。稍微介绍下背景,那是在谷歌发布第一版 Chrome 浏览器的一年之前。当时没有使用 CSS 选择器查询 DOM 元素的标准方式,没有标准方式给元素添加视觉动画,IE 倡导的 XMLHttpRequest 接口 也跟其他许多 API 一样,在浏览器之间表现不一致。

jQuery 让 DOM 操作、动画和 AJAX 请求变得简单, 主要是让 web 开发人员能创建出更现代、更动态的体验从而在普通页面中脱颖而出。最重要的是,有了 jQuery,在一种浏览器中内置的 JavaScript 特性在其他浏览器上通常也能工作。在 Github 早期,当它的大部分功能还在不断开发的时候,这让小规模的开发团队能够快速搭建原型和推出新功能,而无需针对每种浏览器调整代码。

jQuery 简洁的接口也被当做蓝本来开发各种扩展库,这些扩展库后来成为 GitHub.com 前端的构建模块: pjaxfacebox

我们会一直感谢 John Resig 和 jQuery 的贡献者们创建和维护了这样一个有用、在当时看来必不可少的库。

之后几年的 Web 标准

在几年时间里,GitHub发展成为一家拥有数百名工程师和一支专注的团队的公司,开始关注向 web 浏览器提供的 JavaScript 代码的体积和质量。我们一直关注的一件事就是技术债务,有时候技术债务会随着依赖项而增长,这些依赖项曾经提供了价值,但是随着时间的推移这些价值会下降。

具体到 jQuery,我们把它跟现代浏览器对 web 标准的快速支持做了对比,发现:

此外,链式语法并不能满足我们编写代码的意图。例如:

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

这种语法写起来简单,但是根据我们的标准,它并没有很好地传达意图。代码作者是想要单个还是多个js-widget 元素?另外,如果我们更新了页面标签内容,不小心漏掉了 js-widget 类名,浏览器会抛出一个异常通知我们有地方出错了吗?默认情况下,当选择器没有匹配的时候,jQuery 会静默地跳过整个表达式;但对我们来说,这种行为是 bug ,而不是功能。

最后,我们想用Flow来标记数据类型以在构建时做静态检查,并得出结论:链式语法不适合做静态检查,因为几乎所有 jQuery 方法调用结果都是相同类型的。我们之所以选择 Flow 而不是其他同类工具,是因为当时 @flow weak 模式允许我们渐进、高效地对基本上无类型的代码库应用类型系统。

总而言之,摆脱 jQuery 意味着我们可以更多地依赖 web 标准,我们的前端开发人员可以把 MDN web 文档 作为实际上的默认文档, 未来可以维护更有弹性的代码,并且最终从我们的压缩包中剔除 30 KB 的依赖,从而缩短页面载入时间和 JavaScript 执行时间。

增量解耦

即使有这么一个最终目标,我们也知道分配所有的资源来用原生 JS 重写一切是不可能的。即便做到了,如此匆忙的工作很可能导致网站功能的倒退,而往后我们又不得不处理掉它们。相反,我们是这样做的:

这些年来,经过这样的努力,我们得以逐渐减少对 jQuery 的依赖,直到不再有一行代码引用它。

Custom Elements

近年来掀起浪潮的一项技术是 Custom Elements:浏览器内置的一个组件库,也就是说用户不需要下载、解析和编译额外的框架。

从 2014 年开始,我们基于 v0 规范创建了一些定制元素。然而,当时标准仍处于变化中,我们并没有投入很多。直到 2017 年 Web Components v1 规范发布,并且在 Chrome 和 Safari 上实现, 我们才开始更大规模采用Custom Elements

在 jQuery 迁移过程中,我们在寻找适合提取出 custom elements 的模式方法。例如,我们把用来展示模态对话框的 facebox 转换成 <details-dialog> 元素

我们追求渐进增强的一般哲学也延伸到 custom elements。这意味着我们尽可能多地保留标记中的内容,并且只在上面添加行为。例如, <local-time> 默认显示原始时间戳,并可升级为转换时间到本地时区。而 <details-dialog>, 当它内嵌于<details> 元素中时,无需 JavaScript 即可交互,但是可以通过增强可访问性来获得升级。

下面是一个如何实现自定义元素<local-time>的示例:

// local-time 元素显示用户当前时区的时间
// 
//
// 用法示例:
//   <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 Components 的一个方面是Shadow DOM。Shadow DOM 的强大特性有可能为 web 释放大量可能性,但这也使得 polyfill 更加难以实现。因为现在的 polyfill 会导致性能损失,即使对于操作与 web components 无关的DOM的代码,我们也不可能在生产中使用它。

Polyfills

这些是帮助我们过渡到使用标准浏览器特性的 polyfill。我们只在绝对必要的情况下才尝试使用这些 polyfill,也就是对过时浏览器提供单独的兼容性 JavaScript 压缩包。

微信公众号:1024 译站
上一篇 下一篇

猜你喜欢

热点阅读