предисловие
Студенты, которые использовали Node.js для разработки, должны были использовать koa из-за его простого и элегантного метода написания в сочетании с богатой экологией сообщества, а многие существующие платформы Node.js основаны на koa для вторичной инкапсуляции. Но когда дело доходит до производительности, мы должны упомянуть известный фреймворк:fastify
, по названию видно, что характеристики у него быстрые, официально даныBenchmarksЕще более нативный, чем Node.jshttp.Server
Даже быстрее.
Ключ к повышению производительности
давайте сначала посмотрим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
Какие утомительные шаги должны пройти, здесь мы ссылаемся на Дуглас Крукфорд (создатель формата JSON)JSON-js
реализовано вstringify
метод.
JSON-js:GitHub.com/Дуглас Кро С…
// 只展示 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-объектов необходимо пройтись по всем массивам и объектам, поочередно определить тип и добавить все ключи""
, и операция кодирования некоторых специальных символов сюда не включена. Однако, если естьschema
После этого эти ситуации станут намного проще.fastify
Официальная сериализация JSON была разделена на склад:fast-json-stringify
, а позже представилajv
Чтобы проверить, здесь, чтобы упростить понимание кода, выберите более раннюю версию: 0.1.0, логика относительно проста и понятна.
fast-json-stringify@0.1.0:GitHub.com/fa body development/happening…
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'
${$String.toString()}
${$Number.toString()}
${$Null.toString()}
`
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 += '${$String(key)}:'
`
// 通过 nested 转化 value
const value = properties[key]
const result = nested(laterCode, name, `.${key}`, value)
code += result.code
laterCode = result.laterCode
if (i < a.length - 1) {
code += 'json += \',\''
}
})
code += `
json += '}'
return json
}
`
code += laterCode
return code
}
function nested (laterCode, name, key, schema) {
var code = ''
var funcName
// 判断 value 的类型,不同类型进行不同的处理
const type = schema.type
switch (type) {
case 'null':
code += `
json += $Null()
`
break
case 'string':
code += `
json += $String(obj${key})
`
break
case 'number':
case 'integer':
code += `
json += $Number(obj${key})
`
break
case 'object':
// 如果 value 为一个对象,需要一个新的方法进行构造
funcName = (name + key).replace(/[-.\[\]]/g, '')
laterCode = buildObject(schema, laterCode, funcName)
code += `
json += ${funcName}(obj${key})
`
break
case 'array':
funcName = (name + key).replace(/[-.\[\]]/g, '')
laterCode = buildArray(schema, laterCode, funcName)
code += `
json += ${funcName}(obj${key})
`
break
default:
throw new Error(`${type} unsupported`)
}
return {
code,
laterCode
}
}
На самом деле это правильноtype
для"object"
изproperties
сделать обход, то дляvalue
Различные типы вторичной обработки, если встречается новый объект, построит новую функцию обработки.
// 如果包含子对象
const stringify = build({
type: 'object',
properties: {
id: { type: 'number' },
info: {
type: 'object',
properties: {
age: { type: 'number' },
name: { type: 'string' },
}
}
}
})
console.log(stringify.toString())
function $main (obj) {
var json = '{'
json += '"id":'
json += $Number(obj.id)
json += ','
json += '"info":'
json += $maininfo(obj.info)
json += '}'
return json
}
// 子对象会通过另一个函数处理
function $maininfo (obj) {
var json = '{'
json += '"age":'
json += $Number(obj.age)
json += ','
json += '"name":'
json += $String(obj.name)
json += '}'
return json
}
Суммировать
Конечно,fastify
Причина, по которой он претендует на быстроту, заключается в том, что внутри есть какие-то другие методы оптимизации, например, он используется в реализации библиотеки маршрутизации.Radix Tree
, объект контекста можно использовать повторно (используяmiddie
библиотека). В этой статье представлена только одна из самых важных и очевидных идей по оптимизации, и я надеюсь, что после ее прочтения вы сможете что-то для себя извлечь.