为什么说 Nest.js 提供了 Express 没有的架构能力?

标签: nest js express | 发表时间:2023-04-19 22:25 | 作者:zxg_神说要有光
出处:https://juejin.cn/frontend

Nest.js 是当前最流行的 Node.js 框架,现在已经 56k star 了

有的同学说,不是还有 express 么?

其实严格来说 express 并不是一个框架,它只是提供了基于中间件的请求响应处理流程。

但它并没有规定代码应该怎么组织,怎么复用,怎么集成各种方案,所以代码能写成各种样子,这对于大项目开发来说是很难维护的。

所以出现了更上层的 node 框架,比如 egg、midway、nest 这些,它们额外提供了架构能力,这类框架也叫企业级开发框架。

nest 是最优秀的 node 企业级开发框架。

其实 nest 的底层也是 express,但它封装出了 IOC、AOP 等架构特性。

我们分别来看一下它提供的这些架构特性:

nest 最主要的特性就是模块机制了,它类似 es module 但又有很多不一样。

es module 是这样的:

  import { a, b } from 'a';

const c = 1;

export { a, c };

而 nest 的 module 机制是这样写:

  import { Module } from '@nestjs/common';
import { aaa } from './aa.module';
import { CatsService } from './cats.service';

@Module({
  imports: [aaa]
  providers: [CatsService],
  exports: [CatsService]
})
export class CatsModule {}

可以 import 别的模块,可以 export 内部的值。

这些内部的值是通过 provider 提供的,其实 import、export 导入导出的都是这些 provider。

这和 es module 也差不多呀?为啥要自己搞一套模块机制?

因为这套模块机制是可以实现自动注入依赖的,也就是 DI(Denpendency Injection),我们说的 IOC (Inverse Of Control)容器就是有这种依赖注入机制的容器。

这俩概念可能你不理解,看个例子就懂了。

我们写个 AppService 类,它有个 getHello 方法,通过 @Injectable 装饰器声明它是可以被注入的。

把它放到 module 的 provider 里:

这里还有个 controller,它是用来处理 http 请求的,也可以被注入:

它在构造器里声明了对 appService 的依赖。

然后我们把这个应用跑起来:

打个断点:

可以看到这时候 AppService 是有值的。

明明我们只是在 controller 里声明了对这个 service 的依赖,并没有 new 这个 AppService 的对象,也没有 new contoller 的时候传入 AppService 对象。

那它是怎么创建的对象,又是怎么注入的依赖呢?

这些就是 Nest 的模块机制提供的特性了,也就是 DI 或者说 IOC 的能力。

自动化创建对象,并且根据依赖关系自动注入。

这样就算你的对象之间的关系再错综复杂也不用自己去 new 和组装,就很方便。

我们再来测试个 import 的例子:

我 import 了一个操作数据库的 module。

然后在这个 module 的一个 Service 里就可以直接用数据库 module 内的做 crud 的 repository 对象了:

也就是说 module 内部的 provider 之间可以相互注入,provider 也可以注入 controller 中用。

如果 import 了别的 module,那也可以注入它 export 的 provider 了。

这就是 nest 自己实现的模块机制和 es module 最大的不同:实现了依赖自动注入。

用了 nest,只要按照它的写法来声明 @Module 和 @Injectable,就可以使用这种 IOC 能力。

而 express 呢?

你需要手动 new 一个个对象,手动组装。

这是 Nest 提供的第一个架构能力:IOC。

接下来是 Nest 提供的第二个架构能力:AOP。

AOP 是 Aspect Oriented Programming,面向切面编程。

切面也就是处理流程中的某个点,在这个点来扩展一些逻辑,比如在 controller 之前加入日志、权限、异常处理等逻辑:

nest 里主要有 4 种切面:

第一个是 Guard:

它是用来在 Controller 之前判断权限,返回 true、false 来表示是否继续:

要声明在 Contoller 上:

第二个是 Interceptor:

它用来在请求前后加入一些逻辑:

也是声明在 Controller 上:

第三个是 Pipe:

它用来在参数传入 Controller 之前做一些转换:

声明在 Contoller 的某个路由上:

第四个是 ExceptionFilter:

处理过程中可能会抛不同的异常,而 ExceptionFilter 就是处理这些异常,返回友好的信息给客户端的:

也是声明在某个路由上:

这就是 nest 提供的 4 种切面,可以声明某种功能的切面,然后加入到任意的处理流程中。因为是有统一的规范的,所以复用起来很容易。

而 express 呢?

并没有抽象出这些切面,所以代码没有规范,复用也比较困难。

这就是 nest 提供的第二种架构能力:AOP。

nest 的第三种架构能力是可以任意切换平台。

前面说,nest 的底层是 express,其实并不准确,nest 并没有和 express 耦合。

它所有的上层代码都是基于一个抽象的接口的:

而这个接口有 express 和 fastify 两种实现:

分别放在 @nestjs/platform-express 和 @nestjs/platform-fastify 包里。

默认用的是 express:

可以灵活切换 http 的底层平台。

不只是 http 可以切换具体的底层平台,websocket 也是,可以切换 socket.io 和 ws:

通过这层层抽象,就达到了不依赖任何一个底层平台的效果:

哪怕有一天,有一个新的 http 库取代了 express,那对 nest 有影响么?

没有,只要加一个新平台的适配器就可以了。

这就是 nest 的架构的强大之处。

而且不只是可以灵活切换 http 和 ws 平台这么简单。

你写的一些 Guard、Exception Filter、Interceptor、Pipe 甚至可以用在 websocket 和微服务里:

可以跨多种上下文来复用代码:

它提供了 ArgumentsHost 类,在切面里拿到它之后,可以判断出当前是什么上下文:

然后切换到对应的上下文来写后面的的逻辑:

这样就实现了切面的跨上下文复用。

那 express 呢?

并没有这种跨多种平台复用代码的一些抽象。

这就是 nest 提供的第三种架构能力:可以任意切换底层平台和执行上下文。

有了这三种架构特性,代码自然会变得松散耦合、易于扩展,易于维护,所以这种 node 框架才叫做企业级开发框架。

总结

nest 是在 express 之上封装的一层,提供了很多架构的能力:

  • IOC:自己实现了模块机制,可以导入导出 provider,实现自动依赖注入,简化了对象的创建
  • AOP:抽象了 Guard、Interceptor、Pipe、Exception Filter 这 4 种切面,可以通过切面抽离一些通用逻辑,然后动态添加到某个流程中
  • 任意切换底层平台:nest 基于 ts 的 interface 实现了不和任何底层平台耦合,http 可以切换 express 和 fastify,websocket 可以切换 socket.io 和 ws。而且 4 种切面也实现了可以跨 http、websocket、微服务来复用。

明显能感受到,用了 nest 之后,代码会变得很容易维护:通用逻辑都放在切面里复用、不同的业务模块放到不同的 Module 里,依赖自动注入,上层不改一行代码就可以切换底层平台。

而且 nest 基于这个架构提供了对各种方案的集成,比如 mq、redis 的集成、比如 graphql 和 websocket、比如 jwt 等。

架构优雅、各种解决方案开箱即用,这就是 nest 声称自己是企业级开发框架的原因。它对标的是 java 里的 spring。

相比之下,express 虽然也能实现各种功能,但是在架构方面,在其他方案的集成的简便性方面,还是不够的。

如果你要开发一个相对复杂的 node 服务,还是用 nest 吧。

相关 [nest js express] 推荐:

使用js服务端语言nodejs和express建个人站点

- - CSDN博客Web前端推荐文章
使用js服务端语言nodejs和express建个人站点. 作者:田想兵 个人网址: http://www.lovewebgames.com. 今天主题很沉重,因为听说京城又在开会,房价上涨,物价也在涨,还有西湖边上的小松鼠被游客踩死了. 所以说点不开心的事让大伙开心一下,记得一个月前,公司破产,为了生计,我不得不再次投入到找工作的大军中,在杭州,可能做IT行业的技工,都想进阿里淘宝这家杭州标志性的企业,我也不例外,于是投了一份资深前端职位的简历.

Oracle的Filter,Nest loop,Merge sort join和Hash join(原创)

- - ITeye博客
按照Merge Sort Join连接的两表地位完全相同. 这种算法会把每个表按照连接列进行排序,生成两个排序集. 然后对两个排序集进行一次遍历便可以得到最终结果集. 这个算法的特点是,每个表都需要排序,排序后都需要遍历一次. 以下面的例子说明,Merge Sort Join的执行过程如下:. 1、根据tabs表的where条件,查找出符合条件的结果集.

Google 收购 Nest,iPod 之父加盟,Android@Home 再现?

- - 爱范儿 · Beats of Bits
iPod 之父 Tony Fadell 与团队成员 Matt Rogers 离开苹果后创建了智能家居品牌 Nest Labs,并分别发布了智能恒温器 Nest 与智能烟雾探测器 Nest Protect,而两款产品皆因为出色的工业设计与超前理念获得业界一致口碑,成为智能家居潮中最具代表性的品牌,而且已被 Google 看上.

無痛安裝 NodeJS 和 Node Framework Express

- Hming - 小惡魔 - 電腦技術 - 工作筆記 - AppleBOY
直接到官網下載 Stable 的版本吧,目前是 node-v0.4.10.tar.gz,也可以先看看 API Document. 安裝 Ububtu 相關套件. 下面會使用最原始的編譯方式,所以必須安裝 g++ 套件,否則下 ./configure 的時候,會吐出來沒有安裝過的套件. 兩種方法:1.用 apt-get install nodejs 2.

SATA Express新接口、数据线图解

- Jerry - cnBeta.COM
SATA-IO组织日前宣布,正在着手制定新的高速SATA标准规范,传输带宽将提升到8Gbps和16Gbps,而为达此目标将在SATA中融入PCI-E技术. 很自然地,SATA接口、数据线也将会因此发生变化. SATA-IO目前已经组建了新的数据线和接口工作组,专门用来为SATA Express制定新的接口、数据线规格,预计2011年底完成.

利用 new relic 监控 express 项目

- - snoopyxdy的博客
最近一个偶然的机会了解到代码剖析分析,何为剖析,我也解释不好就介绍下它的作用,通过作用来理解吧. 比如一个新项目上线,有许多功能,作为开发者和运维人员是不是很想知道各个功能点运行的怎么样,是否有内存泄露,响应是否迅速,各个功能点用户使用的频率等等信息呢. 另外如果发现了某一个功能使用起来特别慢,那我们能快速定位到,到底是数据库执行慢,还是代码性能问题,又或者是服务器内存不足频繁交换引起的呢.

WebView JS 交互

- - ITeye博客
WebView加jquery做页面会怎么样呢. // 创建WebView对象. // 把programList添加到js的全局对象window中,. // 这样就可以使用window.programList来获取数据. * 定义js回调java函数. // 绑定键盘的向上,向下按钮事件触发相应的js事件.

是纠结也是应对:Nest 同时支持 WiFi/ZigBee 是哪般道理?

- - TECH2IPO创见
本文来自 奇笛网 作者全哥 编辑东风. 关于 Nest 的故事传说版本很多. 那么到底有没有谁深入解剖分析过其产品内在的精神实质. 前面,我们在解剖微智能活动中专门深度剖析了 Nest2.0 温控器产品,其中有个重要的发现值得反思,就是 Nest 温控器其实是可以支持 WiFi 和 ZigBee 双通信方式的.

伪装成优盘的 SSD - Super Talent USB 3.0 Express RC8

- chris_ju - Engadget 中国版
因此 Super Talent 为自家 USB 3.0 优盘提供了两个数字:在最佳状态下读取速度可达 270MB/s,而写入速度则来到 240MB/s. 可别将 Super Talent RC8 和一般的优盘混为一谈,事实上它采用完整的 SandForce SSD 控制器,能够同时使用八个 NAND 通道.

基于Node.js、Express和Jscex开发的ToDo网站示例

- 文涛 - 老赵点滴 - 追求编程之美
Jscex的主要使用场景是“JavaScript异步编程”,不过并没有限制是跑在浏览器还是服务器端. 最近Node.js很火热,也刚发布了原生的Windows版,不少同学会用它来做一些网站这样的小程序. 目前用Node.js开发网站最著名的框架是Express,使用起来也是比较容易的. 前段时间看到CNodeJS社区的一篇文章,有同学将一个Python写的ToDo列表网站移植到了Node.js上,我为了推广Jscex,就fork了这个项目,将其修改为基于Jscex的版本,大伙儿可以来比较一下.