我让 Express 比 Fastify 更快(JSON 速度快 100 倍,NestJS 也一样)
大纲
你好,我是typia的开发人员,fastify
目前正在学习。
在学习过程中,我理解了为什么fastify
比 更快。此外,我还做了一个实验,用typia 更快的 JSON stringify 函数来模拟express
的秘密。fastify
express
从实验(基准测试)中,我得到了有趣的结果,它express
比 更快fastify
。所以我想和大家分享一下。
速度
express
比fastify
什么是typia
// RUNTIME VALIDATORS
export function is<T>(input: unknown | T): input is T; // returns boolean
export function assert<T>(input: unknown | T): T; // throws TypeGuardError
export function validate<T>(input: unknown | T): IValidation<T>; // detailed
export const customValidators: CustomValidatorMap; // can add custom validators
// STRICT VALIDATORS
export function equals<T>(input: unknown | T): input is T;
export function assertEquals<T>(input: unknown | T): T;
export function validateEquals<T>(input: unknown | T): IValidation<T>;
// JSON
export function application<T>(): IJsonApplication; // JSON schema
export function assertParse<T>(input: string): T; // type safe parser
export function assertStringify<T>(input: T): string; // safe and faster
// +) isParse, validateParse
// +) stringify, isStringify, validateStringify
// MISC
export function random<T>(): Primitive<T>; // generate random data
export function clone<T>(input: T): Primitive<T>; // deep clone
export function prune<T extends object>(input: T): void; // erase extra props
// +) isClone, assertClone, validateClone
// +) isPrune, assertPrune, validatePrune
在讲述详细的故事之前,我先简单介绍一下typia 。
它是一个 TypeScript 的运行时验证器库,仅需一行代码,即可使用纯 TypeScript 类型实现上述功能。而其他所有替代库都需要额外且重复的模式定义,这与 TypeScript 类型不同。
此外, typia的验证速度比其他工具快得多。就验证速度而言,typia最多比 快 15,000 倍class-validator
。在 JSON 字符串化函数方面,typia最多比 快 100 倍class-transformer
,甚至是类型安全的。
秘密fastify
fastify是一个竞技库express
,以更快的速度作为武器。
而之所以比isfastify
更快的原因之一是fast-json-stringify。这是团队开发的另一个库,它通过分析 JSON 模式定义来提高 JSON 转换速度。express
fast-json-stringify
fastify
通过使用该fast-json-stringify
库,fastify
可以比 更快地序列化 JSON 字符串express
,并且这种差异使得fastify
比 更快express
。
const fastJson = require('fast-json-stringify')
// REQUIRES JSON SCHEMA DEFINITION
const stringify = fastJson({
title: 'Example Schema',
type: 'object',
properties: {
firstName: {
type: 'string'
},
lastName: {
type: 'string'
},
age: {
description: 'Age in years',
type: 'integer'
},
reg: {
type: 'string'
}
}
});
// MAKES JSON SERIALIZATION FASTER
console.log(stringify({
firstName: 'Matteo',
lastName: 'Collina',
age: 32,
reg: /"([^"]|\\")*"/
}));
fast-json-stringify
JSON.stringify()
比本机函数更快
fastify
模仿的秘密express
import typia from "typia";
// PURE TYPESCRIPT TYPE
interface IPerson {
firstName: string;
lastName: string;
age: number; // Age in years
reg: RegExp;
}
// EASIER THAN ANY OTHER LIBRARIES
typia.stringify<IPerson>({
firstName: 'Matteo',
lastName: 'Collina',
age: 32,
reg: /"([^"]|\\")*"/
});
研究的源代码fastify
,我明白了为什么fastify
更快。
顺便说一下,typia 的功能和 一样fast-json-stringify
。因此,模仿 的秘密fastify
也很容易。
//----
// EXPRESS + TYPIA
//----
import express from "express";
import typia from "typia";
const server: express.Express = express();
const reply =
<T>(stringify: (input: T) => string | null) =>
(data: T) =>
(_req: express.Request, res: express.Response) =>
res
.status(200)
.header("Content-Type", "application/json")
.send(stringify(data));
// VERY EASY TO IMPLEMENT
server.get(
"/ObjectSimple",
reply(typia.createIsStringify<ObjectSimple[]>())
(storage.ObjectSimple),
);
这是使用typiafastify
模仿库的代码。express
我认为我的解决方案比 容易得多fastify
,因为typia不需要复杂的 JSON 模式定义,它只需要纯 TypeScript 类型。
你同意?
//----
// FASTIFY
//----
import fastify, { FastifyReply, FastifyRequest } from "fastify";
import typia from "typia";
const server = fastify();
const schema = (app: typia.IJsonApplication) => {
const definitions: Record<string, typia.IJsonSchema> = {};
for (const [key, value] of Object.entries(app.components.schemas))
definitions[key.replace("#/definitions/", "")] = value;
return {
schema: {
response: {
200: {
...app.schemas[0]!,
definitions,
},
},
},
};
};
const reply = (data: object) => (_i: FastifyRequest, o: FastifyReply) =>
o.send(data);
// DEFINING JSON SCHEMA IS A TERRIBLE WORK
// THEREFORE, I JUST USED typia.application() FUNCTION
server.get(
"/ObjectSimple",
schema(typia.application<[ObjectSimple[]], "ajv", "#/definitions">()),
reply(storage.ObjectSimple),
);
另外,为了进行实验(基准测试)fastify
,我还编写了服务器代码fastify
。顺便说一句,由于定义 JSON 模式对我来说是一项非常繁琐的工作,所以我直接通过typia.application()
函数生成了 JSON 模式数据。
通过autocannon(团队构建的另一个库)测量这些服务器的基准fastify
,我得到了非常棒的结果。在某些情况下,仅仅通过利用函数,express
速度就变得更快。fastify
typia.stringify()
express
fastify
变得比某些情况下更快
提升 NestJS 服务器速度
class-validator
而且class-transformer
速度非常慢
你知道吗?NestJS 正在使用class-validator
和class-transformer
。你还记得吗?在上述基准测试中,这些库比任何其他库都慢。
如果您将它们替换为nestia ( typia为 NestJS 提供的包装器)支持的装饰器,则可以提升您使用 NestJS 开发的后端服务器的速度。只需替换一些如下所示的装饰器函数,您的服务器程序就会运行得更快。
import { Controller } from "@nestjs/common";
import { TypedBody, TypedRoute } from "@nestia/core";
import type { IBbsArticle } from "@bbs-api/structures/IBbsArticle";
@Controller("bbs/articles")
export class BbsArticlesController {
/**
* Store a new content.
*
* @param inupt Content to store
* @returns Newly archived article
*/
@TypedRoute.Post() // 100x faster and safer JSON.stringify()
public async store(
// 15,000x faster validator
@TypedBody() input: IBbsArticle.IStore
): Promise<IBbsArticle>;
// do not need DTO class definition,
// just fine with interface
}
此外,使用nestia,您可以构建比 Swagger 更先进的 Swagger。此外,您还可以构建 SDK 库(例如 tRPC),因此客户端开发人员可以更轻松、更安全地使用您的 API,如下所示。
前端开发人员会很高兴
fastify
仍然很快
回顾上面的基准测试结果,当响应数据较少时, 比和fastify
的组合更快。如果响应数据变得更小,总是比+更快。express
typia
fastify
express
typia
我只是假设它对fastify
标头解析有特殊的优化逻辑,可以减少每次 API 调用的等待时间,但我不知道具体原因。我需要fastify
进一步研究,也需要学习express
。
我会fastify
继续,并且会带着原因再次回来。
感谢您阅读我的文章,希望您喜欢我的文章。
链接
- Github 仓库
- 基准程序
- 基准测试结果