本文将介绍在客户端 JavaScript 环境(即在网络浏览器中运行的代码)中框架和库之间的区别。不过,本文中提出的一些要点也适用于其他环境,因为库和框架是许多软件工程领域(例如原生移动应用开发)的一部分。
本文的讨论重点是库和框架之间的定性差异,而不是定量差异。例如:
- 定量:框架通常遵循控制反转原则。
- 定性:在求职时,框架经验可以让未来的雇主更为青睐。
为何需要了解库和框架?
JavaScript 库和框架在 Web 上被广泛使用。其他所有网站似乎都在其 JavaScript 资源中使用了一些第三方代码。网页加载时间越来越长,这会影响用户。JavaScript 是影响整体网页大小的重要因素,而第三方库和框架通常就是由 JavaScript 组成。
仅仅说“停止使用 JavaScript 框架”是不够的,因为框架为开发者带来了巨大的好处。框架可以帮助您高效编码、快速交付功能,还能带来其他好处。相反,您应该自行学习,以便在需要时做出明智的决定。
您不妨问自己一个不常见的问题:“我今天应该使用库还是框架?”库和框架是两码事。不过,库和框架经常被混为一谈,因此您对这两者的了解越多,就越有可能做出明智的使用决策。
库和框架示例
您可能会看到第三方代码的其他名称,例如 widget、插件、polyfill 或软件包。不过,它们通常都属于库或框架类别。基本上,这两者的区别可以总结如下:
- 对于库,您的应用代码会调用库代码。
- 对于框架,您的应用代码会被框架调用。
库
库通常比框架更简单,提供的功能范围较窄。如果您向方法传递输入并接收输出,则可能使用了库。
请查看 lodash
库的以下示例:
import lodash from 'lodash'; // [1]
const result = lodash.capitalize('hello'); // [2]
console.log(result); // Hello
与许多库一样,仔细阅读此代码并了解其用途非常有用。其中的魔法很少:
import
语句会将 lodash 库导入 JavaScript 程序。- 系统会调用
capitalize()
方法。 - 系统会将一个参数传递给该方法。
- 返回值会捕获在变量中。
框架
框架通常比库大,对整体网页大小的影响也更大。事实上,框架可以包含库。
此示例展示了一个不含库的简单框架,并使用了 Vue(一种热门 JavaScript 框架):
<!-- index.html -->
<div id="main">
{{ message }}
</div>
<script type="module">
import Vue from './node_modules/vue/dist/vue.esm.browser.js';
new Vue({
el: '#main',
data: {
message: 'Hello, world'
}
});
</script>
如果您将此框架示例与前面的库示例进行比较,可能会发现以下差异:
- 框架代码涵盖多种技术,并将这些技术抽象到自己的 API 中。
- 开发者无法完全控制操作的发生方式和时间。例如,Vue 如何以及何时将
'Hello, world'
字符串写入页面,这些细节都已被抽象化。 Vue
类的实例化会产生一些副作用,这在使用框架时很常见,而库可能会提供纯函数。- 该框架规定了特定的 HTML 模板系统,而不是使用您自己的模板系统。
- 如果您进一步阅读 Vue 框架文档或大多数其他框架文档,就会发现框架如何规定您可以使用的架构模式。JavaScript 框架可以减轻您的认知负担,因为您不必自行解决这些问题。
何时使用库而非框架
阅读库和框架之间的比较后,您可能开始了解何时使用库,何时使用框架:
- 框架可以为开发者降低复杂性。如前所述,框架可以抽象出逻辑、行为,甚至架构模式。在开始新项目时,此功能特别有用。库可以帮助解决复杂性问题,但通常侧重于代码重用。
- 框架作者希望您能够高效工作,因此通常会开发额外的工具、调试软件、全面的指南等资源,帮助您有效使用框架。库作者也希望您能够高效工作,但库中很少有专用工具。
- 大多数框架都提供了一个实用的起点(例如框架或样板),可帮助您快速构建 Web 应用。库会成为您已建立的代码库的一部分。
- 通常,框架会给代码库带来一些复杂性。复杂性并不总是在一开始就显而易见,但可能会随着时间的推移而显现出来。
谨此提醒,您通常不会将库与框架进行比较,因为它们是用于完成不同任务的不同内容。不过,您对这两种广告形式了解得越多,就越能做出最适合您的选择。是否使用框架或库最终取决于您的要求。
可切换性
您不会每周更改库或框架。不过,最好了解将您锁定在其生态系统中的软件包的缺点。我们还建议您了解,决定使用第三方软件包的开发者在某种程度上有责任在软件包与应用源代码之间建立松散耦合。
与源代码相关联的软件包更难移除并替换为其他软件包。在以下情况下,您可能需要交换软件包:
- 您必须更新不再受维护的软件包。
- 您发现该软件包存在太多 bug,无法使用。
- 您可以了解更能满足您需求的新套餐。
- 您的产品要求发生变化,不再需要该软件包。
请参考下面的示例:
// header.js file
import color from '@package/set-color';
color('header', 'dark');
// article.js file
import color from '@package/set-color';
color('.article-post', 'dark');
// footer.js file
import color from '@package/set-color';
color('.footer-container', 'dark');
前面的示例在三个单独的文件中使用了第三方 @package/set-color
软件包。如果您要处理此代码并需要替换第三方软件包,则必须在三个位置更新代码。
或者,您也可以简化维护工作,并将库使用情况提取到一个位置,如以下示例所示:
// lib/set-color.js file
import color from '@package/set-color';
export default function color(element, theme = 'dark') {
color(element, theme);
}
// header.js file
import color from './lib/set-color.js';
color('header');
// article.js file
import color from './lib/set-color.js';
color('.article-post');
// footer.js file
import color from './lib/set-color.js';
color('.footer-container');
在前面的示例中,直接库用法已被抽象化。因此,如果您必须替换第三方软件包,只需更新一个文件即可。此外,由于内部 set-color.js
文件设置了要使用的默认配色主题,因此代码现在更易于使用。
易用性
框架可能具有复杂的 API,但可以提供开发者工具,从而让整体使用变得更简单。易用性取决于多种因素,并且可能具有高度主观性。框架可能难以使用,原因如下:
- 该框架的 API 本身就很复杂。
- 该框架的文档不完善,需要反复尝试才能解决问题。
- 该框架使用了您和您的团队不熟悉的技术。
框架可以通过常见的最佳实践来缓解这些挑战,例如:
- 该框架提供了开发者和诊断工具,以简化调试。
- 该框架拥有一个活跃的开发者社区,他们会共同协作,制作免费的文档、指南、教程和视频。了解这些内容后,您便可以高效地使用该框架。
- 该框架提供了一个遵循常见编码规范的 API。由于您之前学习过此类惯例,并且对编码风格越来越熟悉,因此您可以高效地使用该框架。
虽然这些问题通常归因于框架,但也可能归因于库。例如,D3.js JavaScript 库功能强大,拥有庞大的生态系统,其中提供了研讨会、指南和文档等资源,这些资源都会影响其易用性。
此外,框架通常会为您的 Web 应用规定架构,而库通常与您现有的架构(无论是哪种架构)兼容。
性能
一般来说,框架对性能的影响比库更大,但也有例外情况。网站性能是一个包含许多主题的庞大领域,因此以下部分将介绍两个值得注意的主题:树摇动和软件更新。
摇树
捆绑只是 Web 性能的一个方面,但对性能有很大影响,尤其是对于较大的库而言。在导入和导出期间使用树摇动有助于提升性能,因为它会查找并修剪应用不需要的代码。
在打包 JavaScript 代码时,有一个称为“树摇动”的实用步骤,这是一个对代码进行的非常有价值的性能优化,不过,与框架相比,使用库更容易执行此操作。
将第三方代码导入源代码时,您通常会将代码捆绑到一个或多个输出文件中。例如,header.js
、footer.js
和 sidebar.js
文件都会合并到 output.js
文件中,该文件就是您在 Web 应用中加载的输出文件。
如需更好地了解树摇动,请参考以下代码示例:
// library.js file
export function add(a, b) {
return a + b;
}
export function subtract(a, b) {
return a - b;
}
// main.js file
import {add} from './library.js';
console.log(add(7, 10));
出于演示目的,与您在实际环境中可能遇到的库(长度可能有数千行)相比,library.js
代码示例刻意保持较小。
简单的软件包流程可能会使用以下输出导出代码:
// output.js file
function add(a, b) {
return a + b;
}
function subtract(a, b) {
return a - b;
}
console.log(add(7, 10));
虽然此应用不需要 subtract()
函数,但它仍包含在最终软件包中。此类不必要的代码会增加下载大小、解析和编译时间,以及用户必须支付的执行费用。基本树摇方法会移除死代码并生成以下输出:
// output.js file
function add(a, b) {
return a + b;
}
console.log(add(7, 10));
请注意,代码更短、更简洁。在此示例中,性能提升可以忽略不计,但在库长达数千行的实际应用中,性能影响可能更为显著。有趣的是,Parcel、Webpack 和 Rollup 等现代软件包工具更进一步,因为它们结合了缩减和树摇动来创建高度优化的软件包。为了演示软件包工具的有效性,我们使用 Parcel 创建了包含前面代码示例的软件包文件。Parcel 移除了所有未使用的代码,并导出了此单个模块:
console.log(7+10);
Parcel 足够智能,可以移除导入语句、函数定义和行为等内容,以创建高度优化的代码。
捆绑只是 Web 性能的一个方面,但对性能有很大影响,尤其是对于较大的库而言。通常,使用库进行树摇动比使用框架更简单。
软件更新
对于许多库和框架,软件更新会添加功能、修复 bug,并最终随着时间的推移而变大。下载更新并不总是必要的,但如果更新包含 bug 修复、所需的功能增强或安全修复,则您可能应该进行更新。不过,您通过网络发送的数据越多,应用的性能就越低,对用户体验的影响就越大。
如果库的大小不断增加,您可以使用树摇动来减缓这种增长。或者,您也可以使用体积较小的 JavaScript 库替代方案。如需了解详情,请参阅可切换性。
如果框架变大,不仅会增加树摇动方面的挑战,还会增加将一个框架换成另一个框架的难度。如需了解详情,请参阅可切换性。
就业能力
众所周知,许多公司对熟悉特定框架的开发者都有硬性要求。他们可能会忽略您对 Web 基础知识的了解,而只关注您对某个 JavaScript 框架的具体知识!无论对错与否,这都是许多工作的现实。
了解一些 JavaScript 库对您的求职申请没有坏处,但也无法保证能让您脱颖而出。如果您非常熟悉几个热门的 JavaScript 框架,那么在当前的 Web 开发者求职市场中,雇主很可能会认为您具备这方面的知识。有些大型企业组织仍在使用非常陈旧的 JavaScript 框架,甚至可能非常迫切地需要熟悉此类框架的候选人。
您可以利用以下公开的秘密为自己谋取利益。不过,在进入职场时,请谨慎行事,并注意以下事项:
- 请注意,如果您在职业生涯中花费大量时间只使用一种框架,就可能会错过学习其他更现代框架的机会。
- 假设某位开发者对软件开发或 Web 开发基础知识了解不深,但被聘为框架开发者。此开发者编写的代码不高效,您可能会发现处理这样的代码库令人畏惧或不知所措。在某些情况下,这种情况可能会导致倦怠。例如,如果代码运行缓慢,您可能需要重构代码或对其进行性能调优。
- 学习 Web 开发时,最佳途径是先重点学习 Web 开发、软件开发和软件工程的基础知识。如此扎实的基础有助于您快速有效地掌握任何 JavaScript 框架。
总结
您好!您已努力学习,了解了 JavaScript 框架和库的对比情况,非常棒!除非您从事全新项目或担任顾问,否则不必经常选择框架或库。不过,当出现此类决策时,您对相关主题的了解越多,做出的决策就越明智。
正如您所学,您选择的框架(在某些情况下,还包括库)可能会对您的开发体验和最终用户(例如性能)产生重大影响。