溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Node.js服務(wù)性能翻倍秘密是什么

發(fā)布時(shí)間:2021-10-21 16:41:34 來源:億速云 閱讀:123 作者:iii 欄目:web開發(fā)

本篇內(nèi)容主要講解“Node.js服務(wù)性能翻倍秘密是什么”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“Node.js服務(wù)性能翻倍秘密是什么”吧!

前言

用過 Node.js 開發(fā)過的同學(xué)肯定都上手過 koa,因?yàn)樗唵蝺?yōu)雅的寫法,再加上豐富的社區(qū)生態(tài),而且現(xiàn)存的許多 Node.js 框架都是基于 koa  進(jìn)行二次封裝的。但是說到性能,就不得不提到一個(gè)知名框架:fastify ,聽名字就知道它的特性就是快,官方給出的Benchmarks甚至比 Node.js  原生的 http.Server 還要快。

Node.js服務(wù)性能翻倍秘密是什么

Benchmarks

性能提升的關(guān)鍵

我們先看看 fastify 是如何啟動一個(gè)服務(wù)的。

# 安裝 fastify npm i -S fastify@3.9.1
// 創(chuàng)建服務(wù)實(shí)例 const fastify = require('fastify')()  app.get('/', {   schema: {     response: {       // key 為響應(yīng)狀態(tài)碼       '200': {         type: 'object',         properties: {           hello: { type: 'string' }         }       }     }   } }, async () => {   return { hello: 'world' } })  // 啟動服務(wù) ;(async () => {   try {     const port = 3001 // 監(jiān)聽端口     await app.listen(port)     console.info(`server listening on ${port}`)   } catch (err) {     console.error(err)     process.exit(1)   } })()

從上面代碼可以看出,fastify 對請求的響應(yīng)體定義了一個(gè) schema,fastify 除了可以定義響應(yīng)體的 schema,還支持對如下數(shù)據(jù)定義  schema:

  1. 鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)

  2. body:當(dāng)為 POST 或 PUT 方法時(shí),校驗(yàn)請求主體;

  3. query:校驗(yàn) url 的 查詢參數(shù);

  4. params:校驗(yàn) url 參數(shù);

  5. response:過濾并生成用于響應(yīng)體的 schema。

app.post('/user/:id', {   schema: {     params: {       type: 'object',       properties: {        id: { type: 'number' }       }     },     response: {       // 2xx 表示 200~299 的狀態(tài)都適用此 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 默認(rèn)為 application/json   return userInfo })

讓 fastify 性能提升的的秘訣在于,其返回 application/json 類型數(shù)據(jù)的時(shí)候,并沒有使用原生的  JSON.stringify,而是自己內(nèi)部重新實(shí)現(xiàn)了一套 JSON 序列化的方法,這個(gè) schema 就是 JSON 序列化性能翻倍的關(guān)鍵。

如何對 JSON 序列化

在探索 fastify 如何對 JSON 數(shù)據(jù)序列化之前,我們先看看 JSON.stringify 需要經(jīng)過多么繁瑣的步驟,這里我們參考 Douglas  Crockford (JSON 格式的創(chuàng)建者)開源的 JSON-js 中實(shí)現(xiàn)的 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]") {         // 處理數(shù)組         length = value.length;         for (i = 0; i < length; i += 1) {           // 每個(gè)元素都需要單獨(dú)處理           partial[i] = str(i, value) || "null";         }         // 將 partial 轉(zhuǎn)成 ”[...]“         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 轉(zhuǎn)成 "{...}"         v = partial.length === 0           ? "{}"          : "{" + partial.join(",") + "}";         return v;       }   } }

從上面的代碼可以看出,進(jìn)行 JSON 對象序列化時(shí),需要遍歷所有的數(shù)組與對象,逐一進(jìn)行類型的判斷,并對所有的 key 加上  "",而且這里還不包括一些特殊字符的 encode 操作。但是,如果有了 schema 之后,這些情況會變得簡單很多。fastify 官方將 JSON  的序列化單獨(dú)成了一個(gè)倉庫:fast-json-stringify,后期還引入了 ajv  來進(jìn)行校驗(yàn),這里為了更容易看懂代碼,選擇看比較早期的版本: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) {   // 序列化數(shù)組 ... }  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 對外暴露一個(gè) build 方法,該方法接受一個(gè) schema,返回一個(gè)函數(shù)($main),用于將 schema  對應(yīng)的對象進(jìn)行序列化,具體使用方式如下:

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"}

經(jīng)過 build 構(gòu)造后,返回的序列化方法如下:

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 內(nèi)的代碼的:

function buildObject (schema, code, name) {   // 構(gòu)造一個(gè)函數(shù)   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 轉(zhuǎn)化 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 的類型,不同類型進(jìn)行不同的處理   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 為一個(gè)對象,需要一個(gè)新的方法進(jìn)行構(gòu)造       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   } }

其實(shí)就是對 type 為 "object" 的 properties 進(jìn)行一次遍歷,然后針對 value  不同的類型進(jìn)行二次處理,如果碰到新的對象,會構(gòu)造一個(gè)新的函數(shù)進(jìn)行處理。

// 如果包含子對象 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 }  // 子對象會通過另一個(gè)函數(shù)處理 function $maininfo (obj) {   var json = '{'    json += '"age":'    json += $Number(obj.age)   json += ','   json += '"name":'    json += $String(obj.name)    json += '}'   return json }

到此,相信大家對“Node.js服務(wù)性能翻倍秘密是什么”有了更深的了解,不妨來實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI