首页 > 编程语言 >NodeJS框架对比 - Express、Koa、Egg、Nest等

NodeJS框架对比 - Express、Koa、Egg、Nest等

时间:2024-01-31 20:46:43浏览次数:38  
标签:const 框架 NodeJS Koa Nest js app 路由

 

Express.js

Express.js 是 Node.JS 诞生之初,最早出现的一款框架,现在仍然很流行,作者是TJ。 Express是基于回调,也是node中最常见的Error-First 的模式(第一个参数是error对象)

一个简单的Express服务器

查看代码
const express = require('express');
const app = express();

/* 中间件 */
app.use((req, res, next) => {
    console.log('middleware');
    next();
    console.log('middleware call');
});

/* 路由部分 */
const router = express.Router();
router.get('/', (req, res) => {
    res.send('Home');
});

app.use(router);

/* 静态文件 */
app.use(express.static('./'));

app.listen(3000);

随着ECMAScript的发展,推出了generator yield 语法,JS向同步方式写异步代码迈出了一步,作为回应,TJ大神推出了Koa.js。

 

Koa.js

Koa 是一个新的 web 框架,由 Express 幕后的原班人马打造, 致力于成为 web 应用和 API 开发领域中的一个更小、更富有表现力、更健壮的基石。 通过利用 async 函数,Koa 帮你丢弃回调函数,并有力地增强错误处理。 Koa 并没有捆绑任何中间件, 而是提供了一套优雅的方法,帮助您快速而愉快地编写服务端应用程序。 不同于Express,Koa是使用的号称异步终极解决方案的Async/Await,也就是基于Promise,使用Try-Catch来捕获错误。koa与express 提供的API大致相同,express是大而全,内置了大多数的中间件,更让人省心,koa2不绑定任何的框架,干净简洁,小而精,更容易实现定制化,扩展性好。 Koa.js是一款微型Web框架,写一个hello world很简单,但web应用离不开session,视图模板,路由,文件上传,日志管理。这些 Koa 都不提供,需要自行去官方的 Middleware 寻找。然而,100个人可能找出100种搭配。 一个简单的Koa服务器
查看代码
 const Koa = require('koa');
const Router = require('koa-router');
const serve = require('koa-static');

const app = new Koa();
const router = Router();

/* 中间件 */
app.use(async (ctx, next) => {
    console.log('middleware');
    next();
    console.log('middleware call');
});

/* 路由部分 */
router.get('/', (ctx) => {
    ctx.body = 'Home';
});
app.use(router.routes());

/* 静态文件 */
app.use(serve('./'));

app.listen(3000);

 

Koa 对比 Koa2

koa2与koa1的最大区别是koa2实现异步是通过async/await,使用await next()进入下一个中间件;koa1实现异步是通过使用generator函数,yield next进入下一个中间件,而express实现异步是通过回调函数的方式。

 

EGG.js

Egg.js是基于Koa.js,解决了上述问题,将社区最佳实践整合进了Koa.js,另取名叫Egg.js,并且将多进程启动,开发时的热更新等问题一并解决了。这对开发者很友好,开箱即用,开箱即是最(较)佳配置。 Egg.js 是一个约定大于配置的框架 Egg 奉行『约定优于配置』,按照一套统一的约定进行应用开发,团队内部采用这种方式可以减少开发人员的学习成本,开发人员不再是『钉子』,可以流动起来。 正因为如此,Egg.js 中对于目录的规范是有一个约束的,一个基础的 Egg.js 项目的目录结构如下:
egg-project
├── package.json
├── app.js (可选)
├── agent.js (可选)
├── app
|   ├── router.js
│   ├── controller
│   |   └── home.js
│   ├── service (可选)
│   |   └── user.js
│   ├── middleware (可选)
│   |   └── response_time.js
│   ├── schedule (可选)
│   |   └── my_task.js
│   ├── public (可选)
│   |   └── reset.css
│   ├── view (可选)
│   |   └── home.tpl
│   └── extend (可选)
│       ├── helper.js (可选)
│       ├── request.js (可选)
│       ├── response.js (可选)
│       ├── context.js (可选)
│       ├── application.js (可选)
│       └── agent.js (可选)
├── config
|   ├── plugin.js
|   ├── config.default.js
│   ├── config.prod.js
|   ├── config.test.js (可选)
|   ├── config.local.js (可选)
|   └── config.unittest.js (可选)
└── test
    ├── middleware
    |   └── response_time.test.js
    └── controller
        └── home.test.js

 

egg缺点:

  1. 单实例多进程模式,架构异常复杂,为了提升一点点性能,所增加的复杂度完全不可接受。如今serverless的时代,为了性能容器化部署,多实例才是主流。
  1. 开发体验,egg调试体验不太好,打个断点也很困难,调试需要依赖console打印。
  1. 插件机制,万物挂ctx,且不带类型提示(靠别人自觉写d.ts)。插件机制异常黑盒,只能靠配置文件。
  1. 约定大于配置,处处是约定,想整理目录比较困难。如果你更喜欢代码组织以模块为单位,可能会有些不适应。
  1. 生态维护力度很低,完善度也很低,很多插件使用方式很不优雅,不成体系,几乎是在hack。
  1. Egg.js没有原生提供的TypeScript支持, 开发时需要用egg-ts-helper 来帮助自动生成 d.ts 文件
可以尝试一下Nestjs,了解一下ioc,你会发现很多以前组织不好的东西都可以用ioc搞定,这是一套开发逻辑异常统一的工具,理解它会打开新世界的大门。从此就对egg这类不成体系的web框架再无好感,甚至你还顺便理解了Angular的组织方式,去学习使用ng会有豁然开朗的感觉。    

Nest.js

Nestjs 是一个将 Typescript 与 Nodejs Framework 结合的产物。

Nestjs 不是一个新轮子,它是基于 Express、socket.io 封装的 nodejs 后端开发框架,对 Typescript 开发者提供类型支持,也能优雅降级供 Js 使用,拥有诸多特性。Nest是基于Express实现的,需要的话可以取到底层的对象,如requestresponse。 初看 NestJS ,对于 Vue 和 React 技术栈的人来说,NestJS 的思维方式确实不那么容易理解。但是假如你接触过 AngularJS,也许会有一些熟悉感。那要是你曾经是一个后端开发人员,熟练使用 Java 和 Spring 的话,可能就会跳起来大喊一声:这不就是个 Spring boot 吗! 你的直觉没错,NestJS 和 AngularJS,Spring 类似,都是基于控制反转(IoC = Inversion of Control)原则来设计的框架,并且都使用了依赖注入(DI = Dependency Injection)的方式来解决耦合的问题。

Modules, Controllers, Components

Nestjs 开发围绕着这三个单词,Modules 是最大粒度的拆分,表示应用或者模块。Controllers 是传统意义的控制器,一个 Module 拥有多个 Controller。Components 一般用于做 Services,比如将数据库 CRUD 封装在 Services 中,每个 Service 就是一个 Component。

装饰器路由

装饰器路由是个好东西,路由直接标志在函数头上,做到了路由去中心化: 

查看代码
 @Controller()
export class UsersController {
    @Get('users')
    getAllUsers() {}

    @Get('users/:id')
    getUser() {}

    @Post('users')
    addUser() {}
}

装饰器的用法,几乎和java的Spring注解一模一样。以前用过 Go 语言框架 Beego,就是采用了中心化路由管理方式,虽然引入了 namespace 概念,但当协作者多、模块体量巨大时,路由管理成本直线上升。Nestjs 类似 namespace 的概念通过装饰器实现:

@Controller('users')
export class UsersController {
    @Get()
    getAllUsers(req: Request, res: Response, next: NextFunction) {}
}

访问 /users 时会进入 getAllUsers 函数。可以看到其 namespace 也是去中心化的。

模块间依赖注入

Modules, Controllers, Components 之间通过依赖注入相互关联,它们通过同名的 @Module @Controller @Component 装饰器申明,如:

查看代码
 @Controller()
export class UsersController {
    @Get('users')
    getAllUsers() {}
}
@Component()
export class UsersService {
    getAllUsers() {
        return []
    }
}
@Module({
    controllers: [ UsersController ],
    components: [ UsersService ],
})
export class ApplicationModule {}

在 ApplicationModule 申明其内部 Controllers 与 Components 后,就可以在 Controllers 中注入 Components 了:

查看代码
 @Controller()
export class UsersController {
	constructor(private usersService: UsersService) {}

    @Get('users')
    getAllUsers() {
    	return this.usersService.getAllUsers()
    }
}

 

装饰器参数

与大部分框架从 this.req 或 this.context 等取请求参数不同,Nestjs 通过装饰器获取请求参数:

@Get('/:id')
public async getUser(
	@Response() res,
	@Param('id') id,
) {
    const user = await this.usersService.getUser(id);
    res.status(HttpStatus.OK).json(user);
}

@Response 获取 res,@Param 获取路由参数,@Query 获取 url query 参数,@Body 获取 Http body 参数。

 

Midway

Midway 是阿里巴巴 - 淘宝前端架构团队,基于渐进式理念研发的 Node.js 框架。 Midway 基于 TypeScript 开发,结合了面向对象(OOP + Class + IoC)函数式(FP + Function + Hooks)两种编程范式,并在此之上支持了 Web / 全栈 / 微服务 / RPC / Socket / Serverless 等多种场景,致力于为用户提供简单、易用、可靠的 Node.js 服务端研发体验  

为什么要有 Midway

社区上也有很多类似的框架,那为什么还需要 Midway ? 原因有三点
  1. Midway 是阿里内部一直持续在研发的框架,之前 egg 是作为底层框架,需要有面向应用层面的框架来和集团场景对接
  1. 全量使用 TypeScript 是未来一段时间的趋势,面向未来去迭代和研发是作为架构组创新的要求
  1. 虽然社区已经有 nest 这样的框架,但是这些产品的维护、协作、修改都会受到商业化产品的制约,也无法做到需求的快速迭代和安全性保障,整体的研发理念也和我们不同,为此,我们需要有一套自研的框架体系

优势

  1. Midway 框架是在内部已经使用 5 年以上的 Node.js 框架,有着长期投入和持续维护的团队做后盾。
  1. 已经在每年的大促场景经过考验,稳定性无须担心
  1. 丰富的组件和扩展能力,例如数据库,缓存,定时任务,进程模型,部署以及 Web,Socket 甚至 Serverless 等新场景的支持
  1. 一体化调用方案可以方便快捷和前端页面协同开发
  1. 良好的 TypeScript 定义支持
  1. 国产化文档和沟通容易简单

面向对象(OOP + Class + IoC)

Midway 支持面向对象的编程范式,为应用提供更优雅的架构。 下面是基于面向对象,开发路由的示例。
查看代码
 // src/controller/home.ts
import { Controller, Get } from '@midwayjs/decorator';
import { Context } from '@midwayjs/koa';
@Controller('/')
export class HomeController {

  @Inject()  ctx: Context

  @Get('/')  async home() {
    return {
      message: 'Hello Midwayjs!',
      query: this.ctx.ip
    }
	}
}

函数式(FP + Function + Hooks)

Midway 也支持函数式的编程范式,为应用提供更高的研发效率。 下面是基于函数式,开发路由接口的示例。
查看代码
 // src/api/index.ts

import { useContext } from '@midwayjs/hooks'
import { Context } from '@midwayjs/koa';

export default async function home () {
  const ctx = useContext<Context>()

  return {
    message: 'Hello Midwayjs!',
    query: ctx.ip
  }
}
   

NodeJS后端与Java后端对比

NodeJS用于后端开发,对比传统的Java服务端开发有哪些异同。

优势与劣势

  • 优势:占用内存小,启动迅速,不用处理多线程问题,非阻塞高并发,少了Setter Getter和Java各种List/ArrayList/HashMap等...代码编写更简易。
  • 劣势:运行时类型的检查,严谨的类型判断,TypeScript对反射与Decorator功能的支持不足导致框架无法更完善的封装高级功能。

性能

动态语言原来无法和静态语言比性能。 但是nodejs出现 直接把动态语言的性能提升了好几个数量级。V8就是快, 结合跑多个nodejs进程 竟然性能非常好。PHP现在也追了上来,比以前PHP强的多,虽然比nodejs还是差点。

总结

NodeJS后端已经有很好生态,各类工程化与微服务需要功能都有了npm版本,内部数据通过TypeScript验证保证类型无误,只要处理好输入数据的验证和转换问题,是可以在实际项目中发挥力量的。 如果您必须选择一种服务器端技术(Node.js或Spring Boot)来为未来十年的业务提供动力,那会是什么? 人们会说这取决于。如果要构建依赖于大量I / O的应用程序(FinTech,预订系统,媒体应用程序等),则将使用Node.js;但是,如果需要执行大量的计算(物联网,电子商务平台,大数据),那么会使用Spring Boot。 如果赢家只有一个怎么选?Node.js。  

 

参考

https://blog.tangly1024.com/article/nodejs-framework-compare

 

标签:const,框架,NodeJS,Koa,Nest,js,app,路由
From: https://www.cnblogs.com/miangao/p/18000077

相关文章

  • 【NodeJS】- 使用NVM安装npm失败后,手动安装npm
    安装NVM之后,我们通常会配置镜像,在setting文件中,添加镜像路径node_mirror:https://npm.taobao.org/mirrors/nodenpm_mirror:https://npm.taobao.org/mirrors/npm但是这两天镜像突然炸了,于是我删掉了镜像地址,使用官方直接下载。但是npm下载非常困难,而且高版本的npm还存在wo......
  • nodejs 组件引入
    constfs=require("fs");constnodePath=require("path");//import*asfsfrom"fs";constfolder="./";constcondition=["node_modules","compile"];letarr:string[]=[];main(folder,......
  • nodejs下载URL地址的文件后保存以及删除指定文件夹的操作
    这里下载文件用了axios去下载下载:publicasyncdownload_from(url,fileName){returnnewPromise(async(resolve,reject)=>{constdownload_dir=path.join(process.cwd(),AppConfig.config.download_file_path,this._job_id......
  • 为什么nodejs使用forEach下载不是同步下载,使用for却可以同步下载
    这是因为 JavaScript 的 Array.prototype.forEach 方法是同步的,但它不会等待回调函数的异步操作。当你在 forEach 的回调函数中使用异步操作(例如,Node.js 中的下载操作)时,forEach 会立即启动所有操作,而不会等待它们完成。相反,for 循环可以与 async/await 一起使用,以便在......
  • NodeJS Express实现所有页面Http访问重定向跳转为Https
    要在Node.jsExpress中实现所有页面从HTTP访问跳转到HTTPS,你可以使用重定向中间件。以下是一个简单的示例:首先,确保你已经安装了Express和express-redirect中间件。如果没有,你可以通过npm进行安装:npminstallexpressexpress-redirect然后,在你的主应用程序文件(例如app.js)中,引入Expr......
  • nodejs雪花ID算法(SnowflakeID)
    前言项目中常使用的三种id类型,分别是自增id、uuid、雪花id,这三种各有优劣。本篇主要实现nodejs中snowflake算法的代码。一、Snowflake实现这里需要加入big-integer的模块,下载npminstall--save big-integervarSnowflake=(function(){functionSnowflake(_......
  • nodejs带图标的二维码
    前言实现用nodejs生成二维码一、生成二维码先下载qrcode模块,可以使用npminstall--saveqrcode/**@paramstext文本数据@paramscallback回调函数*/vargetQrcode=function(text,callback){constoptions={width:256,height:256,......
  • nodejs实现文件上传
    前言随着前端的发展,本属于后端需要处理的一些功能模块也逐渐可以让前端实现。本篇大致记录一下文件上传功能。一、上传文件这里使用express+multer框架constpath=require('path')constfs=require('fs')constexpress=require('express');//4.18.2constmulter=r......
  • nodejs消费rabbitmq队列消息
    index.jsvaramqp=require('amqplib/callback_api');constMyConsume=require('./MyConsume');amqp.connect('amqp://name:password!@localhost:5672/vhost',function(error0,connection){if(error0){throwerror......
  • Nodejs Http 阻塞业务接口 压测
    consthttp=require('http');//创建一个HTTP服务器constserver=http.createServer((req,res)=>{//设置响应头res.writeHead(200,{'Content-Type':'application/json'});//定义接口路径if(req.url==='/index'){......