JavaScript 库与框架之间的区别

Umar Hansa
Umar Hansa

本文将向您介绍在客户端 JavaScript 环境(即在网络浏览器中运行的代码)背景下框架和库之间的区别。不过,本文中提到的一些要点也适用于其他环境,因为库和框架是许多软件工程领域(例如原生移动应用开发)的一部分。

本博文的讨论重点讨论了性质的差异,而不是库与框架之间的数量差异。例如:

  • 定量:框架通常遵循控制反转原则。
  • 定性:在找工作时,框架经验能够对未来的雇主更有吸引力。

为什么要学习库和框架?

JavaScript 库和框架在网络中非常广泛。其他所有网站似乎都使用一些第三方代码作为其 JavaScript 资源的一部分。网页重量随时间的推移而变得越来越低,这影响了用户JavaScript 是影响整体网页重量的主要因素,而同样包含第三方库和框架的 JavaScript 也是如此。

仅仅说“停止使用 JavaScript 框架”是不够的,因为框架会为开发者带来很大的好处。框架可以帮助您高效编写代码、快速提供功能,以及其他优势。正确的做法是,您应该充实自己,以便日后能够作出明智的决定。

“我今天应该使用库或框架吗?”是一个不常见的问题。库和框架是两种截然不同的东西。然而,库和框架往往混淆在一起,您对这两者的了解越多,就越有可能就其使用做出明智的决定。

库和框架示例

您可能会注意到采用其他名称的第三方代码,例如 widget、插件、polyfill 或软件包。不过,它们通常都属于库或框架的类别。基本上,两者之间的区别可总结如下:

媒体库

库往往比框架更简单,并且提供的功能范围较小。如果您将输入传递给某个方法并收到输出,那么您可能使用了库。

我们来看一下这个 lodash 库示例:

import lodash from 'lodash'; // [1]
const result = lodash.capitalize('hello'); // [2]
console.log(result); // Hello

与许多库一样,通读此代码并了解其功能是切合实际的。这只需要一些很小的魔力:

  1. import 语句会将 lodash 库导入 JavaScript 程序。
  2. 调用 capitalize() 方法。
  3. 系统会向该方法传递一个参数。
  4. 返回值是在变量中捕获的。

框架

框架往往比库大,并且对整体页面重量的贡献更大。实际上,框架可以包含库。

以下示例展示了一个不含库的普通框架,并使用 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 应用。库将成为您现有代码库的一部分。
  • 一般来说,框架会给代码库带来一定程度的复杂性。这种复杂之处在开始时并不总是显而易见的,但随着时间的推移,还会不断显现。

提醒一下,您通常不会将库与框架进行比较,因为库与框架是不同的,用于实现不同的任务。不过,您对这两者了解的越多,就越有能力决定哪一款最适合您。使用框架或库的决定最终取决于您的要求。

可替换性

您无需每周更改库或框架。不过,最好了解软件包的缺点,这会让您受制于其生态系统。此外,建议您了解,决定使用第三方软件包的开发者对在软件包和应用源代码之间创建松散耦合负责。

如果某个软件包与源代码相关联,则较难移除或更换为其他软件包。在以下情况下,您可能需要更换软件包:

  • 您必须对不再维护的软件包进行更新。
  • 您发现该软件包存在错误,无法处理。
  • 您将了解到一种更符合您需求的新软件包。
  • 您的产品要求发生了变化,您不再需要此软件包。

请思考以下示例:

// 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.jsfooter.jssidebar.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() 函数,但它仍包含在最终 bundle 中。这样的不必要代码会增加下载大小、解析和编译时间,以及用户必须支付的执行成本。基本的摇树优化方法会移除死代码并生成以下输出:

// output.js file
function add(a, b) {
  return a + b;
}

console.log(add(7, 10));

请注意,代码更短且更简洁。在此示例中,性能提升可以忽略不计,但在库包含数千行的实际应用中,性能影响可能要显著得多。有趣的是,Parcel、Webpack 和 Rollup 等现代软件包工具更进一步,因为它们结合了缩减大小和摇树优化功能来创建高度优化的软件包。为了展示 bundle 工具的有效性,我们使用 Parcel 根据前面的代码示例创建 bundle 文件。Parcel 移除了所有未使用的代码,并导出了以下模块:

console.log(7+10);

Parcel 非常智能,可以移除 import 语句、函数定义和其他行为,从而创建高度优化的代码。

捆绑只是 Web 性能的一个方面,但它对性能的影响很大,尤其是对于较大的库。使用库进行摇树优化通常比使用框架更简单。

软件更新

对于许多库和框架,软件更新都会添加功能、修复 bug,并最终实现规模的增长。您不一定非要下载更新,但如果更新包含漏洞修复、所需的功能增强或安全修复,那么您应该更新。不过,通过网络发送的数据越多,应用性能就越低,用户体验对性能的影响就越大。

如果库变大,您可以使用摇树优化来减缓增长。或者,您也可以使用 JavaScript 库的较小替代方案。如需了解详情,请参阅可替换性

如果框架变大,不仅摇树优化更大,而且将一个框架换成另一个框架则更加困难。如需了解详情,请参阅可替换性

可雇用情况

许多公司对熟悉特定框架的开发者都有严格的要求,这有点公开秘密。他们可能无视您对网络基础知识的了解,而只专注于您对特定 JavaScript 框架的特定了解!说对错,这是很多工作的现实。

了解一些 JavaScript 库不会对您的求职申请产生负面影响,但无法保证您一定能脱颖而出。如果您非常了解几种流行的 JavaScript 框架,就很有可能雇主认为在 Web 开发者当前的就业市场中,这方面的知识有利。一些大型企业组织一直受限于非常旧的 JavaScript 框架,甚至可能非常希望能够适应此类框架的应聘者。

您可以利用以下公开密钥来获利。然而,在涉入就业市场时应谨慎,并牢记以下注意事项:

  • 请记住,如果您的职业生涯中花费大量时间只使用一种框架,您可能会错失使用其他更现代框架的学习经验。
  • 假设有一位对软件开发或 Web 开发基础知识没有扎实,但被聘为框架开发者的开发者。这位开发者没有编写有效的代码,您可能会发现,处理此类代码库会让人望而生畏,或者让人无所适从。在某些情况下,这种情况可能会导致倦怠。例如,由于运行缓慢,您可能需要重构代码或调整代码性能。
  • 在学习 Web 开发时,最好的办法是先重点关注 Web 开发、软件开发和软件工程的基础知识。这种坚实的基础可帮助您快速有效地掌握任何 JavaScript 框架。

总结

您为了了解 JavaScript 框架和库的比较情况而付出的努力,做得非常好。除非您从事新客户项目或担任顾问,否则您不会经常挑选框架或库。不过,出现此类决定时,您对相应主题了解得越多,做出明智的决定时就越明智。

正如您所了解的,您选择的框架(在某些情况下,选择库)可能会显著影响您的开发体验和最终用户,例如性能。