jQuery 已“死”?为清除技术债,我们删掉了前端所有 jQuery 依赖
近期,英国公共部门站 GOV.UK 前端开发主管 Matt Hobbs 宣布该公司删除了 jQuery 作为所有前端应用程序的依赖项,这意味着“在所有 13 个 FE 应用程序中,JS 大小减少了 32 KB(31% ~49% 之间)”。
Matt 也在推特上分享了几组数据,说明了在删除 jQuery 后一些关键指标得到了优化。
- 移除页面标签限制并查看所有页面 RUM 数据, 75% 用户的页面都有类似的下降:
- 在 75% 的页面中仅检查 Android 用户,可以看到 JS 长任务改进了 7%:
- 50% 用户的移动设备上的 JS Long Tasks 有 10% 的改进:
- 而对于 95% 用户,阻塞时间则减少了 10% :
“这些用户会遇到严重不利的网络和设备条件,每一次性能提升对他们来说尤其重要。”Matt 说道。
根据 Matt 说法,删除 jQuery 的本意是清理技术债。“它最初是为了支持浏览器而存在的,但随着时间的推移,情况发生了变化,所以 bits 可以被删除。我想在这之后会重新评估,看看还有什么是不再需要的。” Matt 表示。
jQuery 是一套跨浏览器的 JavaScript 库,可以简化 HTML 与 JavaScript 之间的操作。截至 2021 年,有将近 84% 的移动页面使用 jQuery。jQuery 是最受欢迎的 JavaScript 库之一,它的一些操作已经反映在标准 Web API 中。
JQuery 创建于 2006 年,主要是为了帮助开发者处理当时浏览器的不足。当时谷歌浏览器还未流行,人们饱受 Internet Explorer 之苦。而 JQuery 开发者可以使用 CSS 选择器和函数可以轻松地遍历和操作 DOM,
此外,JQuery 还提供了一些开箱即用的函数来做动画 DOM 元素,而无需弄乱 CSS。在没有 jQuery 之前发出 AJAX 请求很麻烦,但使用 JQuery 只需几行代码即可完成。JQuery 提供了一个可以在大多数浏览器上工作的 API,这在当时使用 JavaScript 是很难实现的。
但在过去的几年里,JavaScript 已经成熟了很多,它支持很多新的 API,其社区也构建了很多库来填补 jQuery 可能留下的任何空白。
现在,开发者几乎可以在原生 JavaScript 中做任何 jQuery 可以做的事情。例如,可以使用带有 querySelector 和 querySelectorAll 的 CSS 选择器语法来选择元素,使用 classList API 在元素上添加、删除和切换类,使用 addEventListener 将事件处理程序附加到 DOM 元素和窗口等等。
同时随着 Angular、Vue 和 React 等框架的出现和流行,一直未有特别创新的 jQuery 更显“老态”。“对我来说,他们 (jQuery ) 就像是那个随着时代变迁没有更新知识的老灰胡子。”有网友直言。
“现在,大多数事情都不再需要 jQuery 了。”有网友评论道,“我个人发现普通的 JS API 和 fetch 甚至比 jQuery 的东西更干净。人们仍然出于习惯使用 jQuery,是因为摆脱它需要做很多工作。”
近几年,业内对于“jQuery 是否已死”的讨论一直没停过。实际上,一些大型、资金充足的网站已经“用脚投票”,正在逐渐摆脱对 jQuery 的依赖。
2018 年,GitHub 宣布从 GitHub.com 的前端代码中完全移除了 jQuery。“早期,jQuery 对我们意义重大。”GitHub 前端工程团队在方式发布的文章里表示。“在 GitHub 的早期阶段,jQuery 让小型的开发团队能够快速进行原型设计并开发出新功能,而无需专门针对每个 Web 浏览器调整代码。”
但随着 GitHub 成长为一家拥有数百名工程师的公司,jQuery 带来的价值已经随着时间的推移而下降。比如技术债会随着依赖项的增多而增长,给企业带来很大的维护成本。因此,GitHub 最终决定删除 jQuery。不过,GitHub 没有选择另外的库或框架,而是使用标准的浏览器 API 来实现。
不只 GitHub,Bootstrap 最新版本也将删除 jQuery。
尽管被认为已经过时,但 jQuery 仍然是占主导地位的 JavaScript 库。今天的开发人员可能没有意识到在使用 jQuery,因为它被嵌入在了许多大型开源项目里面,其中最著名的就是 WordPress。
“大多数网站都不需要复杂的开发框架,它们大多是具有一些动态行为的静态网站,这种网站通常用 WordPress 编写。jQuery 在这个场景下仍然很流行,因为它既简单又有效,人们觉得没必要停止使用它。”jQuery 开发者 Micha Gobiowski-Owczarek 在接受外媒采访时说道。
Micha Gobiowski-Owczarek 也明确表示,为了不与浏览器冲突,jQuery 不会修改原生原型,而是用 jQuery 包装器对象包装 DOM 节点,每个操作都会创建一个新的包装器对象。大多数情况下,这并不重要,但对于具有大量 DOM 操作的、非常复杂的应用程序来说,可能会成为一个问题。
未来的很长一段时间里,jQuery 还继续会是 WordPress 的一部分,因为它很难在不破坏向后兼容性的情况下将它删除。但一些改变已经发生,如 WordPress 创建的 Gutenberg 编辑器不依赖于 jQuery。
随着时间的推移, WordPress 肯定会逐步更新技术,这是一个渐进的过程,jQuery 的最终去留也很难说。但不可否认的是,jQuery 为前端带来了重大的影响。
参考链接:
https://thenewstack.io/why-outdated-jquery-is-still-the-dominant-javascript-library/
JavaScript 事件冒泡–如何阻止点击事件
什么是JS事件冒泡?
在一个对象上触发某类事件(比如单击onclick事件), 如果此对象定义了此事件的处理程序, 那么此事件就会调用这个处理程序, 如果没有定义此事件处理程序或者事件返回true,
那么这个事件会向这个对象的父级对象传播, 从里到外, 直至它被处理(父级对象所有同类事件都将被激活), 或者它到达了对象层次的最顶层, 即document对象(有些浏览器是window)。
如何来阻止Jquery事件冒泡?
通过一个小例子来解释
比如上面这个页面,
分为三层:divOne是第外层,divTwo中间层,hr_three是最里层;
他们都有各自的click事件,最里层a标签还有href属性。
运行页面,点击“点击我”,会依次弹出:我是最里层—->我是中间层—->我是最外层
—->然后再链接到百度.
这就是事件冒泡, 本来我只点击ID为hr_three的标签, 但是确执行了三个alert操作。
事件冒泡过程(以标签ID表示):hr_three—-> divTwo—-> divOne 。从最里层冒泡到最外层。
如何来阻止?
1.event.stopPropagation();
再点击\”点击我\”, 会弹出:我是最里层, 然后链接到百度
2.return false;
如果头部加入的是以下代码
再点击\”点击我\”, 会弹出:我是最里层, 但不会执行链接到百度页面
由此可以看出:
1.event.stopPropagation();
事件处理过程中,阻止了事件冒泡,但不会默认行为(它就执行了超链接的跳转)
2.return false;
事件处理过程中,阻止了事件冒泡,也阻止了默认行为(比如刚才它就没有执行超链接的跳转)
还有一种有冒泡有关的:
3.event.preventDefault();
如果把它放在头部A标签的click事件中, 点击\”点击我\”。
会发现它依次弹出:我是最里层—->我是中间层—->我是最外层, 但最后却没有跳转到百度
它的作用是:事件处理过程中, 不事件冒泡, 但默认行为(它只执行所有弹框, 却没有执行超链接跳转)
jQuery事件绑定的最佳实践
如果你经常使用jQuery,那么你也许很熟悉事件绑定。这是很基本的东西,但是深入一点,你就能够找到机会让你事件驱动的代码变得不太零碎,并且更容易管理。
更好的选择器策略
让我们从基础的例子开始。下面的HTML代码表示的是可以开合的导航菜单。
<button class=\”nav-menu-toggle\”>Toggle Nav Menu</button>
<nav>
<ul>
<li><a href=\”/\”>West Philadelphia</a></li>
<li><a href=\”/cab\”>Cab Whistling</a></li>
<li><a href=\”/throne\”>Throne Sitting</a></li>
</ul>
</nav>
下面这个是点击按钮之后控制导航菜单开合的javascript代码
$(\’.nav-menu-toggle\’).on(\’click\’,function(){
$(\’nav\’).toggle();
});
这可能是最常用的实现方式。它能够使用,但是比较脆。javascript代码依赖了按钮的类名nav-menu-toggle。很可能在未来其他开发者或者健忘的你在重构代码的时候会删除或者重命名这个类名。
问题的核心是我们同时在表现和交互中使用了CSS的类名。这违反了关注点分离的原则,让维护更容易出错。
让我们用一个不同的方法来实现
<button data-hook=\”nav-menu-toggle\”>Toggle Nav Menu</button>
<nav data-hook=\”nav-menu\”>
<ul>
<li><a href=\”/\”>West Philadelphia</a></li>
<li><a href=\”/cab\”>Cab Whistling</a></li>
<li><a href=\”/throne\”>Throne Sitting</a></li>
</ul>
</nav>
这次我们使用这个data属性(data-hook)来选择元素。任何对CSS类的改变将不会影响到javascript,让我们能够实现关注点分离以及更加稳定的代码。
下面我们用data-hook属性来选择对应的元素:
$(\'[data-hook=\”nav-menu-toggle\”]\’).on(\’click\’,function(){
$(\'[data-hook=\”nav-menu\”]\’).toggle();
});
需要注意的是,我也使用data-hook作为nav元素的选择器。你不一定需要,但是我喜欢这里面包含的思想:任何使用你看到data-hook,你会知道这个元素在javascript中引用到啦。
一些语法
我必须承认data-hook选择器并不是很漂亮。让我们通过扩展jQuery实现一个自定义的函数:
$.extend({
hook:function(hookName){
var selector;
if(!hookName || hookName === \’*\’){
// select all data-hooks
selector=\'[data-hook]\’
}else{
// select specific data-hook
selector=\'[data-hook*=\”\’+hookName+\’\”]\’;
}
return $(selector);
}
});
上面准备完毕,我们来重写一下javascript。
$.hook(\’nav-menu-toggle\’).on(\’\’,function(){
$.hook(\’nav-menu\’).toggle();
});
更好的是,我们甚至可以把一系列以空格分开的hook名字放在一个元素上。
<button data-hook=\”nav-menu-toggle video-pause click-track\”>Toggle Nav Menu</button>
我们可以找到里面的任意个hook名字:
$.hook(\’click-track\’); // returns the button as expected
我们也能够找到页面上所有的hook元素
// both are equivalent
$.hook();
$.hook(\’*\’);
防止函数表达式
到目前为止,我们在事件处理中使用的都是匿名函数。让我们重写一下,使用声明的函数来代替它。
function toggleNavMenu(){
$.hook(\’nav-menu\’).toggle();
}
$.hook(\’nav-menu-toggle\’).on(\’click\’,toggleNavMenu);
这让事件绑定的代码更加易读。这个toggleNavMenu函数名表达了意图,是代码自我注释的好例子。
我们同时也获得了可复用的能力,因为其他地方可能需要使用toggleNavMenu函数。
最后,这对于自动化测试来说是意见大喜事,因为声明的函数的单元测试要比匿名函数单元测试容易的多。
同时使用多个事件
jQuery提供了一个简单方便的语法来处理多事件的问题。比如,你可以为一系列空格隔开的事件列表绑定同一个事件处理函数。
$.hook(\’nav-menu-toggle\’).on(\’click keydown mouseenter\’,trackAction);
如果你需要为不同的事件绑定不同的处理函数,你可以使用对象表达方式:
$.hook(\’nav-menu-toggle\’).on({
\’click\’:trackClick,
\’keydown\’:tranckKeyDown,
\’mouseenter\’:trackMouseEnter
});
反过来,你可以同时取消多个事件的绑定:
// unbinds keydown and mouseenter
$.hook(\’nav-menu-toggle\’).off(\’keydown mouseenter\’);
// nuclear options:unbinds everything
$.hook(\’nav-menu-toggle\’).off();
你可以想象到的是,不小心的取消事件绑定可能会导致严重的我们不想要的副作用。继续看我们可以通过哪些技巧来减轻这个问题。
小心的取消事件绑定
一般情况下我们不会在一个元素的同一事件类型绑定多个事件处理函数。让我们再看一下之前的那个按钮:
<button data-hook=\”nav-menu-toggle video-pause click-track\”>Toggle Nav Menu</button>
不同的代码区域可能会在同一个元素的同一事件绑定不同的事件处理函数:
// somewhere in the nav code
$.hook(\’nav-menu-toggle\’).on(\’click\’,toggleNavMenu);
// somewhere in the video playback code
$.hook(\’video-pause\’).on(\’click\’,pauseCarltonDanceVideo);
// somewhere in the analytics code
$.hook(\’click-track\’).on(\’click\’,trackClick);
尽管我们使用了不同的选择器,但是这个元素现在有三个事件处理函数啦。假如我们的分析代码不在关心这个按钮:
// no good
$.hook(\’click-track\’).off(\’click\’);
糟糕的是,上面的代码实际上回删除所有的点击事件处理函数,不仅仅是trackClick。我们应该实用更加有辨别力的方式来指定我们需要删除的事件处理函数:
$.hook(\’click-track\’).off(\’click\’,trackClick);
另一种方式是使用命名空间。任何事件都有资格使用一个命名空间来实现绑定和取消绑定,这样你就可以更好的控制事件绑定和取消绑定。
// binds a click event in the \”analytics\” namespace
$.hook(\’click-track\’).on(\’click.analytics\’, trackClick);
// unbinds only click events in the \”analytics\” namespace
$.hook(\’click-track\’).off(\’click.analytics\’);
你也可以使用多个命名空间:
// binds a click event in both the \”analytics\” and \”usability\” namespaces
$.hook(\’click-track\’).on(\’click.analytics.usability\’,trackClick);
// unbinds any events in either the \”analytics\” OR \”usability\” namespaces
$.hook(\’click-track\’).off(\’.usability .analytics\’);
// unbinds any events in both the \”analytics\” AND \”usability\” namespaces
$.hook(\’click-track\’).off(\’.usability.analytics\’);
需要注意的是,命名空间的顺序是没有关系的,因为命名空间不是层级式的。
如果你有一个复杂的功能需要多个元素绑定多个事件,那么使用命名空间是一种简单的把一种简单的把他们组织起来然后快速清除的方式:
// free all elements on the page of any \”analytics\” event handling
$(\’*\’).off(\’.analytics\’);
命名空间在写插件的时候尤其有用,因为这样你就能保证只会取消自己命名空间范围内的事件处理函数的绑定。
本文作者及来源:Renderbus瑞云渲染农场https://www.renderbus.com
文章为作者独立观点不代本网立场,未经允许不得转载。