Node.js 服务性能翻倍的秘密(一)

数据库2025-11-04 06:59:0646666

前言

用过 Node.js 开发过的服务翻倍同学肯定都上手过 koa,因为他简单优雅的服务翻倍写法,再加上丰富的服务翻倍社区生态,而且现存的服务翻倍许多 Node.js 框架都是基于 koa 进行二次封装的。但是服务翻倍说到性能,就不得不提到一个知名框架:fastify ,服务翻倍听名字就知道它的服务翻倍特性就是快,官方给出的服务翻倍Benchmarks甚至比 Node.js 原生的 http.Server 还要快。

Benchmarks

性能提升的服务翻倍关键

我们先看看 fastify 是如何启动一个服务的。

# 安装 fastify npm i -S fastify@3.9.1 

// 创建服务实例 const fastify = require(fastify)() app.get(/,服务翻倍 {   schema: {     response: {       // key 为响应状态码       200: {         type: object,         properties: {           hello: { type: string }         }       }     }   } }, async () => {   return { hello: world } }) // 启动服务 ;(async () => {   try {     const port = 3001 // 监听端口     await app.listen(port)     console.info(`server listening on ${port}`)   } catch (err) {     console.error(err)     process.exit(1)   } })() 

从上面代码可以看出,fastify 对请求的服务翻倍响应体定义了一个 schema,fastify 除了可以定义响应体的服务翻倍 schema,还支持对如下数据定义 schema:

body:当为 POST 或 PUT 方法时,服务翻倍校验请求主体; query:校验 url 的服务翻倍 查询参数; params:校验 url 参数; response:过滤并生成用于响应体的 schema。 app.post(/user/:id,服务翻倍 {   schema: {     params: {       type: object,       properties: {        id: { type: number }       }     },     response: {       // 2xx 表示 200~299 的免费信息发布网状态都适用此 schema       2xx: {         type: object,         properties: {           id: { type: number },           name: { type: string }         }       }     }   } }, async (req) => {   const id = req.params.id   const userInfo = await User.findById(id)   // Content-Type 默认为 application/json   return userInfo }) 

让 fastify 性能提升的的秘诀在于,其返回 application/json 类型数据的时候,并没有使用原生的 JSON.stringify,而是自己内部重新实现了一套 JSON 序列化的方法,这个 schema 就是 JSON 序列化性能翻倍的关键。

如何对 JSON 序列化

在探索 fastify 如何对 JSON 数据序列化之前,我们先看看 JSON.stringify 需要经过多么繁琐的步骤,这里我们参考 Douglas Crockford (JSON 格式的创建者)开源的 JSON-js 中实现的 stringify 方法。

“JSON-js:https://github.com/douglascrockford/JSON-js/blob/master/json2.js

// 只展示 JSON.stringify 核心代码,其他代码有所省略 if (typeof JSON !== "object") {   JSON = {}; } JSON.stringify = function (value) {   return str("", {"": value}) } function str(key, holder) {   var value = holder[key];   switch(typeof value) {     case "string":       return quote(value);     case "number":       return (isFinite(value)) ? String(value) : "null";     case "boolean":     case "null":       return String(value);     case "object":       if (!value) {         return "null";       }       partial = [];       if (Object.prototype.toString.apply(value) === "[object Array]") {         // 处理数组         length = value.length;         for (i = 0; i < length; i += 1) {           // 每个元素都需要单独处理           partial[i] = str(i, value) || "null";         }         // 将 partial 转成 ”[...]“         v = partial.length === 0           ? "[]"           : "[" + partial.join(",") + "]";         return v;       } else {         // 处理对象         for (k in value) {           if (Object.prototype.hasOwnProperty.call(value, k)) {             v = str(k, value);             if (v) {               partial.push(quote(k) + ":" + v);             }           }         }         // 将 partial 转成 "{...}"         v = partial.length === 0           ? "{}"          : "{" + partial.join(",") + "}";         return v;       }   } } 

从上面的代码可以看出,进行 JSON 对象序列化时,需要遍历所有的数组与对象,逐一进行类型的判断,并对所有的 key 加上 "",而且这里还不包括一些特殊字符的 encode 操作。高防服务器但是,如果有了 schema 之后,这些情况会变得简单很多。fastify 官方将 JSON 的序列化单独成了一个仓库:fast-json-stringify,后期还引入了 ajv 来进行校验,这里为了更容易看懂代码,选择看比较早期的版本:0.1.0,逻辑比较简单,便于理解。

“fast-json-stringify@0.1.0:https://github.com/fastify/fast-json-stringify/blob/v0.1.0/index.js

function $Null (i) {   return null } function $Number (i) {   var num = Number(i)   if (isNaN(num)) {     return null   } else {     return String(num)   } } function $String (i) {   return " + i + " } function buildObject (schema, code, name) {   // 序列化对象 ... } function buildArray (schema, code, name) {   // 序列化数组 ... } function build (schema) {   var code = `     use strict     $     $     $   `   var main   code = buildObject(schema, code, $main)   code += `     ;     return $main   `   return (new Function(code))() } module.exports = build 

fast-json-stringify 对外暴露一个 build 方法,该方法接受一个 schema,返回一个函数($main),用于将 schema 对应的对象进行序列化,具体使用方式如下:

const build = require(fast-json-stringify) const stringify = build({   type: object,   properties: {     id: { type: number },     name: { type: string }   } }) console.log(stringify) const objString = stringify({   id: 1, name: shenfq }) console.log(objString) // {"id":1,"name":"shenfq"} 

经过 build 构造后,返回的序列化方法如下:

function $String (i) {   return " + i + " } function $Number (i) {   var num = Number(i)   if (isNaN(num)) {     return null   } else {     return String(num)   } } function $Null (i) {   return null } // 序列化方法 function $main (obj) {   var json = {   json += "id":   json += $Number(obj.id)   json += ,   json += "name":   json += $String(obj.name)   json += }   return json } 

可以看到,有 schema 做支撑,序列化的逻辑瞬间变得无比简单,最后得到的 JSON 字符串只保留需要的属性,简洁高效。我们回过头再看看 buildObject 是如何生成 $main 内的代码的:

function buildObject (schema, code, name) {   // 构造一个函数   code += `     function ${name} (obj) {       var json = {   `   var laterCode =    // 遍历 schema 的属性   const { properties } = schema   Object.keys(properties).forEach((key, i, a) => {     // key 需要加上双引号     code += `       json += $云服务器
本文地址:http://www.bzuk.cn/news/380f33899281.html
版权声明

本文仅代表作者观点,不代表本站立场。
本文系作者授权发表,未经许可,不得转载。

全站热门

iPhone5s升级iOS8.1的全面指南(了解如何为iPhone5s安装最新的iOS8.1系统)

简易教程(一步步教你如何使用U盘来启动制作Windows7系统)

华为畅享5X手机测评(一款性价比超高的智能手机)

以PS的亮度为主题探讨如何合适地调整图片亮度(掌握关键步骤让图片更加生动鲜明)

探索oppocoloros2.0(从界面设计到个性化定制,发现coloros2.0的无限魅力)

大神F1Plus(全面升级的F1Plus,一款令人难以抗拒的智能手机选择)

电脑店最新装机教程(从选购零部件到组装,让你成为电脑大师!)

华硕i7笔记本的性能与用户体验(探究华硕i7笔记本的配置与使用感受)

友情链接

滇ICP备2023006006号-33