精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

Node.js 服務性能翻倍的秘密(二)

開發 前端
前一篇文章介紹了 fastify 通過 schema 來序列化 JSON,為 Node.js 服務提升性能的方法。今天的文章會介紹 fastify 使用的路由庫,翻閱其源碼(lib/route.js)可以發現,fastify 的路由庫并不是內置的,而是使用了一個叫做 find-my-way 的路由庫。

[[360400]]

前言

前一篇文章介紹了 fastify 通過 schema 來序列化 JSON,為 Node.js 服務提升性能的方法。今天的文章會介紹 fastify 使用的路由庫,翻閱其源碼(lib/route.js)可以發現,fastify 的路由庫并不是內置的,而是使用了一個叫做 find-my-way 的路由庫。

route.js

這個路由庫的簡介也很有意思,號稱“超級無敵快”的 HTTP 路由。

README

看上去 fastify 像是依賴了第三方的路由庫,其實這兩個庫的作者是同一批人。

author

如何使用find-my-way 通過 on 方法綁定路由,并且提供了 HTTP 所有方法的簡寫。

  1. const router = require('./index')() 
  2.  
  3. router.on('GET''/a', (req, res, params) => { 
  4.   res.end('{"message": "GET /a"}'
  5. }) 
  6. router.get('/a/b', (req, res, params) => { 
  7.   res.end('{"message": "GET /a/b"}'
  8. })) 

其實內部就是通過遍歷所有的 HTTP 方法名,然后在原型上擴展的。

  1. Router.prototype.on = function on (method, path, opts, handler) { 
  2.   if (typeof opts === 'function') { 
  3.     // 如果 opts 為函數,表示此時的 opts 為 handler 
  4.     handler = opts 
  5.     opts = {} 
  6.   } 
  7.   // ... 
  8. for (var i in http.METHODS) { 
  9.   const m = http.METHODS[i] 
  10.   const methodName = m.toLowerCase() 
  11.   // 擴展方法簡寫 
  12.   Router.prototype[methodName] = function (path, handler) { 
  13.     return this.on(m, path, handler) 
  14.   } 

綁定的路由可以通過 lookup 調用,只要將原生的 req 和 res 傳入 lookup 即可。

  1. const http = require('http'
  2.  
  3. const server = http.createServer((req, res) => { 
  4.   // 只要將原生的 req 和 res 傳入 lookup 即可 
  5.   router.lookup(req, res) 
  6. }) 
  7.   
  8. server.listen(3000) 

find-my-way 會通過 req.method/req.url 找到對應的 handler,然后進行調用。

  1. Router.prototype.lookup = function lookup (req, res) { 
  2.   var handle = this.find(req.method, sanitizeUrl(req.url)) 
  3.   if (handle === null) { 
  4.     return this._defaultRoute(req, res, ctx) 
  5.   } 
  6.   // 調用 hendler 
  7.   return handle.handler(req, res, handle.params) 

路由的添加和查找都基于樹結構來實現的,下面我們來看看具體的實現。

Radix Tree

find-my-way 采用了名為 Radix Tree(基數樹) 的算法,也被稱為 Prefix Tree(前綴樹)。Go 語言里常用的 web 框架echo和gin都使用了Radix Tree作為路由查找的算法。

  • 在計算機科學中,基數樹,或稱壓縮前綴樹,是一種更節省空間的Trie(前綴樹)。對于基數樹的每個節點,如果該節點是確定的子樹的話,就和父節點合并。

Radix Tree

在 find-my-way 中每個 HTTP 方法(GET、POST、PUT ...)都會對應一棵前綴樹。

  1. // 方法有所簡化... 
  2. function Router (opts) { 
  3.   opts = opts || {} 
  4.   this.trees = {} 
  5.   this.routes = [] 
  6.  
  7. Router.prototype.on = function on (method, path, opts, handler) { 
  8.   if (typeof opts === 'function') { 
  9.     // 如果 opts 為函數,表示此時的 opts 為 handler 
  10.     handler = opts 
  11.     opts = {} 
  12.   } 
  13.   this._on(method, path, opts, handler) 
  14.  
  15. Router.prototype._on = function on (method, path, opts, handler) { 
  16.   this.routes.push({ 
  17.     method, path, opts, handler, 
  18.   }) 
  19.   // 調用 _insert 方法 
  20.   this._insert(method, path, handler) 
  21.  
  22. Router.prototype._insert = function _insert (method, path, handler) { 
  23.   // 取出方法對應的 tree 
  24.   var currentNode = this.trees[method] 
  25.   if (typeof currentNode === 'undefined') { 
  26.     // 首次插入構造一個新的 Tree 
  27.     currentNode = new Node({ method }) 
  28.     this.trees[method] = currentNode 
  29.   } 
  30.   while(true) { 
  31.     // 為 currentNode 插入新的節點... 
  32.   } 

每個方法對應的樹在第一次獲取不存在的時候,都會先創建一個根節點,根節點使用默認字符(/)。

trees

每個節點的數據結構如下:

  1. // 只保留了一些重要參數,其他的暫時忽略 
  2. function Node(options) { 
  3.   options = options || {} 
  4.   this.prefix = options.prefix || '/' // 去除公共前綴之后的字符,默認為 / 
  5.   this.label = this.prefix[0]         // 用于存放其第一個字符 
  6.   this.method = options.method        // 請求的方法 
  7.   this.handler = options.handler      // 請求的回調 
  8.   this.children = options.children || {} // 存放后續的子節點 

當我們插入了幾個路由節點后,樹結構的具體構造如下:

  1. router.on('GET''/a', (req, res, params) => { 
  2.   res.end('{"message":"hello world"}'
  3. }) 
  4. router.on('GET''/aa', (req, res, params) => { 
  5.   res.end('{"message":"hello world"}'
  6. }) 
  7. router.on('GET''/ab', (req, res, params) => { 
  8.   res.end('{"message":"hello world"}'
  9. }) 

  

GET Tree

  1. Node { 
  2.   label: 'a'
  3.   prefix: 'a'
  4.   method: 'GET'
  5.   children: { 
  6.     a: Node { 
  7.       label: 'a'
  8.       prefix: 'a'
  9.       method: 'GET'
  10.       children: {}, 
  11.       handler: [Function
  12.     }, 
  13.     b: Node { 
  14.       label: 'b'
  15.       prefix: 'b'
  16.       method: 'GET'
  17.       children: {}, 
  18.       handler: [Function
  19.     } 
  20.   }, 
  21.   handler: [Function

如果我們綁定一個名為 /axxx 的路由,為了節約內存,不會生成三個 label 為x 的節點,只會生成一個節點,其 label 為 x,prefix 為 xxx。

  1. router.on('GET''/a', (req, res, params) => { 
  2.   res.end('{"message":"hello world"}'
  3. }) 
  4. router.on('GET''/axxx', (req, res, params) => { 
  5.   res.end('{"message":"hello world"}'
  6. }) 

 

GET Tree

  1. Node { 
  2.   label: 'a'
  3.   prefix: 'a'
  4.   method: 'GET'
  5.   children: { 
  6.     a: Node { 
  7.       label: 'x'
  8.       prefix: 'xxx'
  9.       method: 'GET'
  10.       children: {}, 
  11.       handler: [Function
  12.     } 
  13.   }, 
  14.   handler: [Function

插入路由節點

通過之前的代碼可以看到, on 方法最后會調用內部的 _insert 方法插入新的節點,下面看看其具體的實現方式:

  1. Router.prototype._insert = function _insert (method, path, handler) { 
  2.   // 取出方法對應的 tree 
  3.   var currentNode = this.trees[method] 
  4.   if (typeof currentNode === 'undefined') { 
  5.     // 首次插入構造一個新的 Tree 
  6.     currentNode = new Node({ method }) 
  7.     this.trees[method] = currentNode 
  8.   } 
  9.  
  10.   var len = 0 
  11.   var node = null 
  12.   var prefix = '' 
  13.   var prefixLen = 0 
  14.   while(true) { 
  15.     prefix = currentNode.prefix 
  16.     prefixLen = prefix.length 
  17.     len = prefixLen 
  18.     path = path.slice(len) 
  19.     // 查找是否存在公共前綴 
  20.     node = currentNode.findByLabel(path) 
  21.     if (node) { 
  22.       // 公共前綴存在,復用 
  23.       currentNode = node 
  24.       continue 
  25.     } 
  26.     // 公共前綴不存在,創建一個 
  27.     node = new Node({ method: method, prefix: path }) 
  28.     currentNode.addChild(node) 
  29.   } 

插入節點會調用 Node 原型上的 addChild 方法。

  1. Node.prototype.getLabel = function () { 
  2.   return this.prefix[0] 
  3.  
  4. Node.prototype.addChild = function (node) { 
  5.   var label = node.getLabel() // 取出第一個字符做為 label 
  6.   this.children[label] = node 
  7.   return this 

本質是遍歷路徑的每個字符,然后判斷當前節點的子節點是否已經存在一個節點,如果存在就繼續向下遍歷,如果不存在,則新建一個節點,插入到當前節點。

圖片

tree

查找路由節點

find-my-way 對外提供了 lookup 方法,用于查找路由對應的方法并執行,內部是通過 find 方法查找的。

  1. Router.prototype.find = function find (method, path, version) { 
  2.   var currentNode = this.trees[method] 
  3.   if (!currentNode) return null 
  4.  
  5.   while (true) { 
  6.     var pathLen = path.length 
  7.     var prefix = currentNode.prefix 
  8.     var prefixLen = prefix.length 
  9.     var len = prefixLen 
  10.     var previousPath = path 
  11.     // 找到了路由 
  12.     if (pathLen === 0 || path === prefix) { 
  13.       var handle = currentNode.handler 
  14.       if (handle !== null && handle !== undefined) { 
  15.         return { 
  16.           handler: handle.handler 
  17.         } 
  18.       } 
  19.     } 
  20.     // 繼續向下查找 
  21.     path = path.slice(len) 
  22.     currentNode = currentNode.findChild(path) 
  23.   } 
  24.  
  25. Node.prototype.findChild = function (path) { 
  26.   var child = this.children[path[0]] 
  27.   if (child !== undefined || child.handler !== null)) { 
  28.     if (path.slice(0, child.prefix.length) === child.prefix) { 
  29.       return child 
  30.     } 
  31.   } 
  32.  
  33.   return null 

查找節點也是通過遍歷樹的方式完成的,找到節點之后還需要放到 handle 是否存在,存在的話需要執行回調。

總結

本文主要介紹了 fastify 的路由庫通過 Radix Tree 進行提速的思路,相比于其他的路由庫通過正則匹配(例如 koa-router 就是通過 path-to-regexp 來解析路徑的),效率上還是高很多的。

 

責任編輯:姜華 來源: 更了不起的前端
相關推薦

2020-12-14 15:40:59

Nodefastifyjs

2020-12-14 08:55:00

Node.js服務性框架

2025-07-21 01:00:00

UDP性能QPS

2019-07-09 14:50:15

Node.js前端工具

2013-11-01 09:34:56

Node.js技術

2015-03-10 10:59:18

Node.js開發指南基礎介紹

2022-08-28 16:30:34

Node.jsDocker指令

2021-12-25 22:29:57

Node.js 微任務處理事件循環

2020-10-12 08:06:28

HTTP 服務器證書

2022-08-22 07:26:32

Node.js微服務架構

2012-02-03 09:25:39

Node.js

2020-05-29 15:33:28

Node.js框架JavaScript

2015-11-04 09:18:41

Node.js應用性能

2015-12-14 10:39:14

2011-09-02 14:47:48

Node

2011-11-01 10:30:36

Node.js

2011-09-08 13:46:14

node.js

2011-09-09 14:23:13

Node.js

2012-10-24 14:56:30

IBMdw

2011-11-10 08:55:00

Node.js
點贊
收藏

51CTO技術棧公眾號

青青青草网站免费视频在线观看| 亚洲女人天堂成人av在线| 色婷婷综合成人| 欧美另类videosbestsex日本| 国产性生活毛片| 国产三级视频在线播放线观看| 婷婷综合网站| 东方欧美亚洲色图在线| 日韩一区二区三区在线视频| 欧美大陆一区二区| www.99热| 人成在线免费网站| 国产1区2区3区精品美女| 另类天堂视频在线观看| 奇米影视四色在线| 国产一区电影| 久久免费黄色| 精品亚洲aⅴ在线观看| 国产亚洲黄色片| 午夜精品一二三区| 亚洲精品99| 欧美精品粉嫩高潮一区二区| 午夜精品视频在线观看一区二区| 91精品国产高清一区二区三密臀| 久久亚州av| 午夜精品久久久| 国产伦精品一区二区三区照片91 | 精品久久久影院| 亚洲日本理论电影| 正在播放木下凛凛xv99| 九九免费精品视频在线观看| 五月激情丁香一区二区三区| 国产精品一区二区三区四区五区| 波多野结衣mp4| 国产系列电影在线播放网址| 国产精品一级黄| 久久av.com| 日韩一区二区a片免费观看| 在线亚洲人成| 国产三级一区二区| 国产精品九九九| 波多野结衣一二三四区| 国产毛片精品久久| 国产精品福利一区二区| 91亚洲永久免费精品| 免费无遮挡无码永久在线观看视频| 精品中文在线| 午夜伊人狠狠久久| 伊人再见免费在线观看高清版 | 欧美一级欧美三级| 手机在线免费观看毛片| 欧洲日本在线| 国产黑丝在线一区二区三区| 午夜精品久久久久久99热软件| 三级黄色片网站| 日本美女久久| 亚洲色图欧美激情| 5g国产欧美日韩视频| 欧美爱爱小视频| 福利片在线一区二区| 色嗨嗨av一区二区三区| 自拍另类欧美| 天天干天天做天天操| 老司机午夜精品视频在线观看| 91国在线精品国内播放| 自拍偷拍你懂的| 亚洲高清在线一区| 色老综合老女人久久久| 久久久噜噜噜www成人网| 91福利在线视频| 国产老女人精品毛片久久| 91精品视频免费看| 国产伦子伦对白视频| 99亚洲视频| 久久精品视频在线| 中文字幕av网址| 日本精品在线播放| 精品剧情在线观看| 天堂久久久久久| 国产中文字幕一区二区三区| 日韩精品一区二区三区swag| 久草在在线视频| 黑人精品视频| 中文字幕在线观看不卡| 免费观看黄色的网站| 国产高清视频免费最新在线| 国产欧美精品一区二区色综合朱莉 | 91精品国产91久久综合桃花 | 亚洲羞羞网站| 91免费国产视频网站| 成人有码视频在线播放| 国产伦精品一区二区三区视频网站| 久久经典综合| 欧美激情精品久久久久久| 男人天堂资源网| 亚洲色图网站| 色婷婷综合久久久久| 青娱乐国产在线视频| 香蕉亚洲视频| 97福利一区二区| 97人妻精品视频一区| 性8sex亚洲区入口| 国产日本欧美视频| 自拍偷拍色综合| 国产精品18久久久久久vr| 精品视频一区二区三区四区| 蜜桃91麻豆精品一二三区| 日韩专区一卡二卡| 欧美性做爰毛片| 日韩精品在线不卡| 激情六月综合| 欧美激情在线一区| 久久久久久天堂| 一区二区三区四区在线观看国产日韩 | 欧美熟妇精品一区二区| 日本中文字幕视频一区| 欧美午夜电影网| 国产天堂在线播放| h视频久久久| 亚洲精品在线观看视频| 在线中文字日产幕| 精品三级av在线导航| 色偷偷亚洲男人天堂| 日韩精品久久久久久久酒店| 宅男噜噜噜66国产日韩在线观看| 91精品国产自产在线老师啪| 欧美日韩伦理片| 日本一区二区三级电影在线观看| 欧美另类videosbestsex日本| 成人免费在线观看视频| 欧美三区在线视频| 亚洲午夜精品一区| 香蕉大人久久国产成人av| 这里只有精品在线播放| 四季av中文字幕| 亚洲欧美大片| 国产亚洲福利社区| 精品欧美不卡一区二区在线观看 | 成年永久一区二区三区免费视频| 欧美三级免费观看| 北条麻妃av高潮尖叫在线观看| av成人资源| 久久av红桃一区二区小说| 中文字幕在线观看欧美| 久久久久久久精| 亚洲欧美日韩精品久久久| 麻豆传媒视频在线观看| 欧美伊人久久久久久午夜久久久久| 在线免费观看a级片| 精品99在线| 久久午夜a级毛片| 在线视频欧美亚洲| 成人免费视频一区| 800av在线免费观看| 日韩性xxx| 日韩一区和二区| 手机在线中文字幕| 亚洲激情二区| 国产精品三级久久久久久电影| 国产欧美一区二区三区视频在线观看| 国产精品无人区| 日韩一级免费看| 日韩精品一区国产| 欧美福利视频在线| 欧美一区二区黄片| 福利二区91精品bt7086| 亚欧激情乱码久久久久久久久| 欧美色蜜桃97| 国内免费久久久久久久久久久 | 一区二区三区福利| 精品午夜一区二区三区| 暖暖成人免费视频| 日韩在线免费视频| 国产高中女学生第一次| 26uuu精品一区二区三区四区在线| 日韩欧美国产综合在线| 欧美高清你懂的| 久久精品国产久精国产思思| 国产人妖一区二区| 亚洲图片自拍偷拍| 91在线第一页| 欧美亚洲在线日韩| 成人国内精品久久久久一区| 18+视频在线观看| 色悠久久久久综合欧美99| 欧美xxxx日本和非洲| 日韩天天综合| 台湾成人av| 日韩精品成人在线观看| 91国产美女视频| 成人免费高清在线播放| 亚洲va国产天堂va久久en| 99久久久久久久久久| 麻豆精品视频在线观看免费| 久久亚洲综合网| h1515四虎成人| 欧美多人爱爱视频网站| 久草视频在线看| 91精品在线免费| 免费看污片网站| 一本色道久久综合亚洲精品不卡| 日本精品二区| 波多野结衣在线观看| 亚洲欧美日韩国产中文| 97人妻一区二区精品免费视频| 91在线视频免费91| 9色视频在线观看| 亚洲精品国产精品粉嫩| 国精产品一区一区三区有限在线| 激情小说 在线视频| 欧美电视剧在线看免费| 中文字幕一区二区三区四区欧美| 亚洲男同1069视频| 蜜桃视频无码区在线观看| 久久都是精品| 久久男人资源站| 日韩三级在线| 国产主播在线一区| 自拍网站在线观看| 亚洲欧美国产日韩中文字幕| 国产三级漂亮女教师| 色婷婷国产精品久久包臀| 欧美日韩精品在线观看视频 | 日韩一级片网站| 亚洲国产成人精品女人久久| 久久亚洲欧美国产精品乐播| av免费中文字幕| 国产精品vip| 国产99视频精品免费视频36| 免费高潮视频95在线观看网站| 日韩在线播放av| 国产人妖一区二区三区| 欧美在线高清视频| 精品免费囯产一区二区三区 | 久精品国产欧美| 色综合桃花网| 久久99国产综合精品女同| 亚洲精品一区二区三区四区| 性久久久久久久久| 一区二区成人免费视频| 国内久久精品视频| 日韩精品一区二区免费| 亚洲精品网址| 免费看啪啪网站| 久久综合99| 粉嫩精品一区二区三区在线观看 | 国产精品日日摸夜夜添夜夜av| 中日韩脚交footjobhd| 久久免费少妇高潮久久精品99| 日本在线视频中文有码| 久久国产精品免费视频| 秋霞av鲁丝片一区二区| 日韩三级高清在线| 精品国产av鲁一鲁一区| 日韩一区二区电影| 成 人 黄 色 片 在线播放| 日韩午夜三级在线| 亚洲av无码乱码国产精品| 欧美成人国产一区二区| 不卡视频免费在线观看| 精品国产三级a在线观看| 丰满人妻一区二区| 亚洲国产精品福利| 国产孕妇孕交大片孕| 欧美日韩亚州综合| 国产理论视频在线观看| 日韩一区二区三区精品视频| 性欧美8khd高清极品| 亚洲国产精品成人精品| 欧美3p视频在线观看| 一区二区亚洲欧洲国产日韩| 人妻一区二区三区| 日韩精品免费视频| wwwxxxx国产| 亚洲电影av在线| 免费国产在线观看| 日韩在线播放av| 成人爽a毛片免费啪啪动漫| 欧美自拍视频在线| 精精国产xxxx视频在线中文版 | 96精品久久久久中文字幕| 瑟瑟视频在线看| 欧洲亚洲在线视频| 国产精品久久久久久久久久齐齐| 91久久精品久久国产性色也91| 超碰一区二区三区| 欧美久久在线| 中文字幕午夜精品一区二区三区| 国产一级爱c视频| 亚洲老妇激情| 久久综合色视频| 精品电影一区| 激情婷婷综合网| 国产精品一卡| 欧美精品久久久久久久久久久| 久久国产直播| www激情五月| 91玉足脚交白嫩脚丫在线播放| 国产三级在线观看完整版| 一区二区三区日本| 特级片在线观看| 一本久久a久久免费精品不卡| 国产裸体永久免费无遮挡| 亚洲激情第一页| 丰满岳乱妇国产精品一区| 亚洲人av在线影院| 日韩a在线观看| 久久精品国产亚洲一区二区| xx欧美视频| 亚洲自拍高清视频网站| 国内精品久久久久久久久电影网| 欧美一级特黄aaaaaa在线看片| 水野朝阳av一区二区三区| 欧美熟妇精品一区二区| 国产精品国产精品国产专区不蜜 | 免费观看在线午夜影视| 91超碰caoporn97人人| 精品国产一区二区三区性色av| 欧日韩一区二区三区| 亚洲国产二区| 色噜噜狠狠一区二区三区狼国成人| 久久亚洲捆绑美女| 日本三级网站在线观看| 91精品国产欧美一区二区18| 国产九九在线| 51精品在线观看| 丁香综合av| 精品人妻人人做人人爽| 久草精品在线观看| 中文字幕第10页| 成人性生交大合| 乱h高h女3p含苞待放| 欧美日韩一区在线| 黄网在线免费| 欧美中文在线字幕| 精品人人人人| 日本福利视频一区| 高清av一区二区| 欧美日韩大片在线观看| 91精品在线免费| 理论片午午伦夜理片在线播放| 国产精品入口尤物| 日韩中文在线电影| 国产九九在线视频| 国产精品国产三级国产普通话蜜臀 | 欧美精品一卡| 少妇人妻无码专区视频| 国产成人综合网| 久草视频在线免费看| 日韩午夜av电影| 日韩三级免费| 粉嫩高清一区二区三区精品视频| 欧美精选在线| 97精品人人妻人人| 亚洲444eee在线观看| 日韩中文字幕免费在线观看| 久久久久久久久久久网站| 国产精品流白浆在线观看| 欧美亚洲黄色片| bt7086福利一区国产| 国产不卡在线观看视频| 欧美亚洲尤物久久| 99中文字幕一区| 成人国产精品久久久久久亚洲| 国产韩日影视精品| 午夜影院免费版| 亚洲福利视频一区二区| 在线观看毛片av| 日韩中文视频免费在线观看| **精品中文字幕一区二区三区| 国产精品一区在线免费观看| 男女精品网站| 丁香花五月婷婷| 51精品国自产在线| 毛片网站在线看| 久久偷窥视频| 麻豆91精品视频| 中国毛片直接看| 欧美亚洲禁片免费| 麻豆视频在线观看免费网站| 99在线视频免费观看| 99久久亚洲精品| 一区二区三区四区影院| 黄网动漫久久久| av网站无病毒在线| 91成人在线看| 亚洲欧美视频| 免费黄色激情视频| 亚洲黄色有码视频| 99久久久国产精品免费调教网站| 可以免费看的黄色网址| 99re成人精品视频| 一区二区www| 深夜福利一区二区| 超碰国产精品一区二页| 日韩av综合在线观看| 自拍偷拍欧美精品| 在线观看日批视频| 国产69精品久久久久9| 成人看的视频|