成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

使用Node.js實現(xiàn)一個express框架

開發(fā) 前端
本文介紹了如何使用Node.js來實現(xiàn)一個express框架的,一起來看看吧。

 [[336666]]

手寫一個express系列

express的基本用法 

  1. const express = require("express");  
  2. const app = express();  
  3. app.get("/test", (req, res, next) => {  
  4.   console.log("*1");  
  5. //   res.end("2");  
  6.   next();  
  7. });  
  8. app.get("/test", (req, res, next) => {  
  9.   console.log("*2");  
  10.   res.end("2");  
  11. });  
  12. app.listen(8888, (err) => {  
  13.   !err && console.log("監(jiān)聽成功");  
  14. }); 
  •  當(dāng)我訪問localhost:8888/test時候,返回了:2,服務(wù)端打印了 
  1. *1  
  2. *2 
  •  從上面可以看到什么?
    •  express默認引入調(diào)用后返回一個app對象
    •  app.listen 會啟動進程監(jiān)聽端口
    •  每次收到請求,對應(yīng)的url和method會觸發(fā)相應(yīng)掛載在app上對應(yīng)的回調(diào)函數(shù)
    •  調(diào)用 next 方法,會觸發(fā)下一個

一起來實現(xiàn)一個簡單的express框架

  •  定義屬于我們的express文件入口,這里使用class來實現(xiàn) 
  1. class express {  
  2.  
  3. module.exports = express
  •  需要的原生模塊http,創(chuàng)建進程監(jiān)聽端口 
  1. const { createServer } = require("http"); 
  •  給 class 定義 listen 方法,監(jiān)聽端口 
  1. class express {  
  2.   listen(...args) {  
  3.     createServer(cb).listen(...args);  
  4.   }  
  •  這樣就可以通過調(diào)用 class 的 listen 去調(diào)用 http 模塊的 listen 了,這里的cb我們可以先不管,你要知道每次接受到請求,必然會調(diào)用 cb 函數(shù),這個是 createServer 原生模塊幫我們封裝好的

實現(xiàn)接收到請求觸發(fā)

  •  實現(xiàn)app.get app.post等方法
    •  目前我們接受到響應(yīng),就會觸發(fā) cb 這個回調(diào)函數(shù),那我們打印下,看看是什么參數(shù)? 
  1. class express {  
  2.   cb() {  
  3.     return (req, res) => {  
  4.       console.log(res, res, "開始行動");  
  5.     };  
  6.   }  
  7.   listen(...args) {  
  8.     createServer(this.cb()).listen(...args);  
  9.   }  
  •  發(fā)現(xiàn)此時的 req 和 res 正是我們想要的可讀流和可寫流.
  •  開始編寫 get 和 post 方法
    •  這里注意,有路由是'/'的,這種是不管任何路由都會觸發(fā)一次 
  1. constructor() {  
  2.     this.routers = {  
  3.       get: [],  
  4.       post: [],  
  5.     };  
  6.   }  
  7.   get(path, handle) {  
  8.     this.routers.get.push({  
  9.       path,  
  10.       handle,  
  11.     });  
  12.   }  
  13.   post(path, handle) {  
  14.     this.routers.post.push({  
  15.       path,  
  16.       handle,  
  17.     });  
  18.   } 
  •  初始化時候定義 get、post 的數(shù)組儲存對應(yīng)的 path 和 handle.
  •  需要觸發(fā)路由回調(diào)的時候,首先要找到對應(yīng)的請求方式下對應(yīng)的 url 的 handle 方法,然后觸發(fā)回調(diào).
  •  如何找到對應(yīng)請求方式下的 url 對應(yīng)的 handle 方法? 在接到請求時候就要遍歷一次
    •  這里要考慮匹配多個路由,意味著,我們可能遇到像最開始一樣,有兩個 get 方式的 test 路由 
  1. cb() {  
  2.   return (req, res) => {  
  3.     const method = req.method.toLowerCase();  
  4.     console.log(this.routers[method], ",method");  
  5.     const url = req.url;  
  6.     this.routers[method].forEach((item) => {  
  7.       item.path === url && item.handle(req, res);  
  8.     });  
  9.   };  
  10.  
  11. listen(...args) {  
  12.   createServer(this.cb()).listen(...args);  
  •  上面根據(jù) method 找到對應(yīng)的數(shù)組,遍歷找到請求的路由,觸發(fā)回調(diào),此時已經(jīng)能正常返回數(shù)據(jù)了 
  1. [ { method: 'get', path: '/test', handle: [Function] } ] ,method 
  •  此時最簡單的express已經(jīng)完成了,但是我們好像忘了最重要的中間件

完成最重要的中間件功能

  •  首先要知道,express中間件分兩種,一種帶路由的,那就是根據(jù)路由決定是否觸發(fā)
  •  另外一種就是不帶路由的,像靜態(tài)資源這種. 是用戶訪問任何路由都要觸發(fā)一次的
  •  那我們需要一個 all 數(shù)組儲存這種任意路由都需要匹配觸發(fā)的 
  1. constructor() {  
  2.    this.routers = {  
  3.      get: [],  
  4.      post: [],  
  5.      all: [],  
  6.    };  
  7.  } 
  •  之前的直接通過 push 方式是太粗暴.如果用戶需要中間件功能,不傳路由,那就要做特殊處理,這里通過一個中間函數(shù)處理下
  •  改造get、post方法,定義handleAddRouter方法 
  1. handleAddRouter(path, handle) {  
  2.    let router = {}; 
  3.     if (typeof path === "string") {  
  4.      router = {  
  5.        path,  
  6.        handle,  
  7.      };  
  8.    } else {  
  9.      router = {  
  10.        path: "/",  
  11.        handle: path, 
  12.      };  
  13.    }  
  14.    return router;  
  15.  }  
  16.  get(path, handle) {  
  17.    const router = this.handleAddRouter(path, handle);  
  18.    this.routers.get.push(router);  
  19.  }  
  20.  post(path, handle) {  
  21.    const router = this.handleAddRouter(path, handle);  
  22.    this.routers.post.push(router); 
  23.   }  
  24.  use(path, handle) {  
  25.    const router = this.handleAddRouter(path, handle);  
  26.    this.routers.all.push(router);  
  27.  } 
  •  每次添加之前,先觸發(fā)一次handleAddRouter,如果是 path 為空的中間件,直接傳入函數(shù)的,那么 path 幫它設(shè)置成'/'
  •  我們還遺留了一個點,next的實現(xiàn),因為我們現(xiàn)在加了all這個數(shù)組后,意味著可能有多個中間件,那么可能一次請求打過來,就要觸發(fā)多個路由

這里要注意,promise.then 源碼實現(xiàn)和 express 的 next、以及 koa 的洋蔥圈、redux 的中間件實現(xiàn),有著一丁點相似,當(dāng)你能真的領(lǐng)悟前后端框架源碼時候,發(fā)現(xiàn)大都相似

  •  閱讀我的文章,足以擊破所有前后端源碼.而且可以手寫出來, 我們只學(xué)最核心的,抓重點學(xué)習(xí),野蠻生長!

實現(xiàn)next

  •  思路:
    •  首先要找到所有匹配的路由
    •  然后逐個執(zhí)行(看 next 的調(diào)用)
  •  定義search方法,找到所有匹配的路由 
  1. search(method, url) {  
  2.     const matchedList = [];  
  3.     [...this.routers[method], ...this.routers.all].forEach((item) => {  
  4.       item.path === url && matchedList.push(item.handle);  
  5.     });  
  6.     return matchedList;  
  7.   }  
  8.   cb() {  
  9.     return (req, res) => {  
  10.       const method = req.method.toLowerCase();  
  11.       const url = req.url;  
  12.       const matchedList = this.search(method, url);  
  13.     };  
  14.   } 
  •  matchedList就是我們想要找到的所有路由
  •  為了完成next,我們要將req ,res , matchedList存入閉包中,定義handle方法 
  1. handle(req, res, matchedList) {  
  2.    const next = () => {  
  3.      const midlleware = matchedList.shift();  
  4.      if (midlleware) {  
  5.        midlleware(req, res, next);  
  6.      }  
  7.    };  
  8.    next();  
  9.  }  
  10.  cb() {  
  11.    return (req, res) => {  
  12.      const method = req.method.toLowerCase();  
  13.      const url = req.url;  
  14.      const matchedList = this.search(method, url);  
  15.      this.handle(req, res, matchedList);  
  16.    };  
  17.  } 
  •  這樣我們就完成了next方法,只要手動調(diào)用 next 就會調(diào)用下一個匹配到的路由回調(diào)函數(shù)
  •  不到一百行代碼,就完成了這個簡單的express框架

寫在最后

  •  只要你根據(jù)我這些文章去認真自己實現(xiàn)一次,一年內(nèi)拿個 P6 應(yīng)該沒什么問題
  •  大道至簡,希望你能通過這些文章真的學(xué)到框架的原理,進而自己能寫出一些框架,走向更高的層級
  •  我是Peter,曾經(jīng) 20 萬人超級群桌面軟件的架構(gòu)師,現(xiàn)在就職于明源云,擔(dān)任分公司前端負責(zé)人,目前深圳這邊需要招聘兩位中高級前端,3D數(shù)據(jù)可視化方向,期待你的到來
  •  如果感覺本文對你有幫助,別忘了點個在看和關(guān)注. 我們的技術(shù)團隊也會不斷產(chǎn)出原創(chuàng)文章, 一起見證各位的成長 

 

責(zé)任編輯:龐桂玉 來源: segmentfault
相關(guān)推薦

2011-10-25 09:28:30

Node.js

2022-10-18 18:43:40

Node.js低代碼

2017-04-24 08:31:26

Node.jsExpress.jsHTTP

2019-04-15 11:00:46

框架Node.JS開發(fā)

2020-05-29 15:33:28

Node.js框架JavaScript

2023-05-12 07:31:58

NuxtVue.js

2020-07-15 08:06:04

Node.js框架開發(fā)

2021-07-16 04:56:03

NodejsAddon

2014-07-11 14:16:15

AbsurdJSExpress

2020-10-29 16:00:03

Node.jsweb前端

2021-08-20 16:05:28

JavaScript node.js 應(yīng)用安全

2019-08-29 10:58:02

Web 開發(fā)框架

2022-05-23 10:26:50

Node.jsJavaScrip

2011-06-17 10:29:04

Nodejavascript

2022-06-05 13:52:32

Node.jsDNS 的原理DNS 服務(wù)器

2020-02-25 12:27:59

Node.jsWeb開發(fā)前端

2014-04-10 09:43:00

Node.jsTwilio

2022-08-28 16:30:34

Node.jsDocker指令

2012-03-07 14:32:41

Node.js

2014-10-30 10:28:55

Node.js
點贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 一区二区三区四区国产精品 | 国产亚洲一区二区三区 | 精品中文字幕视频 | 欧美区在线 | 一级片av | 久久久精品视频免费 | 日韩超碰在线 | 亚洲精品久久久久久久久久久 | 久久精品国产免费高清 | 精品一区二区久久久久久久网站 | 日韩一区二区三区四区五区六区 | www.国产日本 | 午夜免费看 | 成人免费在线视频 | 国产男女视频网站 | 久久av一区 | 亚洲成人一区二区在线 | 国产中的精品av涩差av | 欧洲视频一区二区 | 黄片毛片 | 国产精品久久久久久久7电影 | 欧美中文字幕在线观看 | 亚洲va欧美va人人爽午夜 | 激情小视频 | 久久精品国产精品青草 | 欧美不卡网站 | 精品久久国产 | 国产线视频精品免费观看视频 | 亚洲日本中文字幕在线 | 久久久一区二区三区 | www.天天操| av在线播放网站 | 99av成人精品国语自产拍 | 不卡的av在线| 亚洲精品日韩一区二区电影 | 欧美影院| 久久成人免费 | 四虎影院新地址 | 久久精品一区二区三区四区 | 国产精品久久久久久久久久久免费看 | 99国产精品久久久 |