zoukankan      html  css  js  c++  java
  • 实现自己的Koa2

    这部分的代码在https://github.com/zhaobao1830/koa2中demo文件夹中

    Koa就是基于node自带的http模块,经过封装,监听端口,实现ctx(上下文)管理,中间件管理等

    例子1、koa监听3000端口,在页面输出值

     1 const Koa = require('koa')
     2 const app = new Koa()
     3 
     4 app.use((ctx,next) => {
     5   ctx.body = 'hello koa2'
     6 })
     7 
     8 app.listen(3000, function () {
     9   console.log('启动3000端口')
    10 })

    ctx 是封装了request和response的上下文

    next  的作用就是执行下一个中间件

    APP  启动应用

    例子2、http监听3000端口,页面返回值

    1 const http = require('http')
    2 
    3 const server = http.createServer((req,res) => {
    4   res.writeHead('200')
    5   res.end('hello node')
    6 })
    7 server.listen(3000, function () {
    8   console.log('启动了3000端口')
    9 })

    例子3、使用http封装一个简单的web服务

     1 const http = require('http')
     2 
     3 class application{
     4   constructor() {
     5     this.callback = () => {}
     6   }
     7 
     8   use(callback) {
     9     this.callback = callback
    10   }
    11 
    12   listen(...args) {
    13     const server = http.createServer((req,res) => {
    14       this.callback(req, res)
    15     })
    16     server.listen(...args)
    17   }
    18 }
    19 
    20 module.exports = application
     1 const Koa3 = require('./index3')
     2 const app = new Koa3()
     3 
     4 app.use((req,res) => {
     5   res.writeHead(200)
     6   res.end('hello Koa3')
     7 })
     8 
     9 app.listen(3003, function () {
    10   console.log('启动3003端口')
    11 })

    例子4:

    koa2中的ctx就是上下文,用来挂载request和response对象

    js的get和set方法

     1 const yese = {
     2   _name: '夜色',
     3   get name() {
     4     return this._name
     5   },
     6   set name(val) {
     7     console.log('new name is' + val)
     8     this._name = val
     9   }
    10 }
    11 
    12 console.log(yese.name)
    13 yese.name = '荷塘月色'
    14 console.log(yese.name)

    加入ctx上下文,封装了http里的request和response

         index7.js

     1 const http = require('http')
     2 
     3 //req是http模块里的
     4 let request = {
     5   get url () {
     6     return this.req.url
     7   }
     8 }
     9 
    10 let response = {
    11   get body () {
    12     return this._body
    13   },
    14   set body (val) {
    15     this._body = val
    16   }
    17 }
    18 
    19 // 把上面定义的request和response挂载到context对象中
    20 let context = {
    21    get url () {
    22      return this.request.url
    23    },
    24    get body () {
    25      return this.response.body
    26    },
    27   set body (val) {
    28      this.response.body = val
    29   }
    30 }
    31 
    32 
    33 class application{
    34   constructor() {
    35     // 把上面定义的context,request,response挂载到application中
    36     this.context = context
    37     this.request = request
    38     this.response = response
    39   }
    40 
    41   use(callback) {
    42     this.callback = callback
    43   }
    44   listen(...args) {
    45     const server = http.createServer(async (req, res) => {
    46       let ctx = this.createCtx(req,res)
    47       await this.callback(ctx)
    48       ctx.res.end(ctx.body)
    49     })
    50     server.listen(...args)
    51   }
    52   createCtx (req, res) {
    53     let ctx = Object.create(this.context)
    54     ctx.request = Object.create(this.request)
    55     ctx.response = Object.create(this.response)
    56     // 把http里的req赋值给ctx.request的req和ctx.req上
    57     ctx.req = ctx.request.req = req
    58     ctx.res = ctx.response.req = res
    59     return ctx
    60   }
    61 }
    62 
    63 module.exports = application

    调用

     1 const Koa3 = require('./index7')
     2 const app = new Koa3()
     3 
     4 app.use(async (ctx) => {
     5   ctx.body = 'hello Koa2 '+ ctx.url
     6 })
     7 
     8 app.listen(3003, function () {
     9   console.log('启动3003端口')
    10 })

     例子5、(这个例子是同步的)compose中间件

     1 function add(x, y) {
     2   return x + y
     3 }
     4 function double(z) {
     5   return z*2
     6 }
     7 
     8 const middlewares = [add, double]
     9 let len = middlewares.length
    10 // 中间件
    11 function compose(midds) {
    12   console.log('midds:'+midds)
    13    return (...args) => {
    14     console.log(...args)
    15      // 初始值
    16      let res = midds[0](...args)
    17      console.log(res)
    18      for (let i = 1; i < len; i++) {
    19        res = midds[i](res)
    20      }
    21      return res
    22    }
    23 }
    24 const fn = compose(middlewares)
    25 const res = fn(1,2)
    26 console.log(res)

     例子6、

     自己实现的一个简单的compose代码

     1 async function fn1(next) {
     2   console.log('fn1')
     3   await next()
     4   console.log('end fn1')
     5 }
     6 async function fn2(next) {
     7   console.log('fn2')
     8   await delay()
     9   await next()
    10   console.log('end fn2')
    11 }
    12 function fn3() {
    13   console.log('fn3')
    14 }
    15 
    16 function delay() {
    17   return new Promise((resolve, reject) => {
    18     setTimeout(() => {
    19       resolve()
    20     }, 2000)
    21   })
    22 }
    23 
    24 function compose (middlewares) {
    25   return function () {
    26     return dispatch(0)
    27     
    28     function dispatch(i) {
    29       let fn = middlewares[i]
    30       if(!fn) {
    31         return Promise.resolve()
    32       }
    33       // 这俩行是compose的核心代码
    34       return Promise.resolve(fn(function next() {
    35         return dispatch(i+1)
    36       }))
    37     }
    38   }
    39   
    40 }
    41 
    42 const middlewares = [fn1, fn2, fn3]
    43 
    44 const finalfn = compose(middlewares)
    45 finalfn()

    运行结果为:

    个人理解:核心就是先执行方法里的值,遇到了next(),就执行下一层的(koa2是一个类似洋葱圈的结构)

    index11.js

     1 const http = require('http')
     2 
     3 //req是http模块里的
     4 let request = {
     5   get url () {
     6     return this.req.url
     7   }
     8 }
     9 
    10 let response = {
    11   get body () {
    12     return this._body
    13   },
    14   set body (val) {
    15     this._body = val
    16   }
    17 }
    18 
    19 // 把上面定义的request和response挂载到context对象中
    20 let context = {
    21   get url () {
    22     return this.request.url
    23   },
    24   get body () {
    25     return this.response.body
    26   },
    27   set body (val) {
    28     this.response.body = val
    29   }
    30 }
    31 
    32 
    33 class application{
    34   constructor() {
    35     // 把上面定义的context,request,response挂载到application中
    36     this.context = context
    37     this.request = request
    38     this.response = response
    39     this.middlewares = []
    40   }
    41 
    42   use(callback) {
    43     this.middlewares.push(callback)
    44     // this.callback = callback
    45   }
    46   compose (middlewares) {
    47     return function (context) {
    48       return dispatch(0)
    49 
    50         function dispatch(i) {
    51           let fn = middlewares[i]
    52           if(!fn) {
    53             return Promise.resolve()
    54           }
    55           // 这俩行是compose的核心代码
    56           return Promise.resolve(fn(context, function next() {
    57             return dispatch(i+1)
    58           }))
    59         }
    60     }
    61   }
    62   listen(...args) {
    63     const server = http.createServer(async (req, res) => {
    64       let ctx = this.createCtx(req,res)
    65       const fn = this.compose(this.middlewares)
    66       await fn(ctx)
    67       ctx.res.end(ctx.body)
    68     })
    69     server.listen(...args)
    70   }
    71   createCtx (req, res) {
    72     let ctx = Object.create(this.context)
    73     ctx.request = Object.create(this.request)
    74     ctx.response = Object.create(this.response)
    75     // 把http里的req赋值给ctx.request的req和ctx.req上
    76     ctx.req = ctx.request.req = req
    77     ctx.res = ctx.response.req = res
    78     return ctx
    79   }
    80 }
    81 
    82 module.exports = application
     1 const Koa3 = require('./index11')
     2 const app = new Koa3()
     3 
     4 function delay() {
     5   return new Promise((resolve, reject) => {
     6     setTimeout(() => {
     7       resolve()
     8     }, 2000)
     9   })
    10 }
    11 
    12 app.use(async (ctx, next) => {
    13   ctx.body = '1'
    14   await next()
    15   ctx.body += '2'
    16 })
    17 
    18 app.use(async (ctx, next) => {
    19   ctx.body += '3'
    20   await delay()
    21   await next()
    22   ctx.body += '4'
    23 })
    24 
    25 app.use(async (ctx, next) => {
    26   ctx.body += '5'
    27 })
    28 
    29 app.listen(3003, function () {
    30   console.log('启动3003端口')
    31 })

    运行结果: 

    打开页面 2秒以后出现:13542 (async await要等异步的操作都执行完,才会输出结果)

    Koa2的其他知识

     

    app.use()就算是一个中间件
    中间件概念:一个http请求是:发起请求request,返回结果response,中间的部分就可以理解为中间件
  • 相关阅读:
    一个简单而经典的RTX51 Tiny应用实例
    基于HttpClient 4.3的可訪问自签名HTTPS网站的新版工具类
    动态绑定与动态分发-动态绑定暗含动态分发
    多态是面向接口编程的概念
    多态本质:多个对象共享同一接口 多态本质是共享接口
    Smalltalk
    Simula-Virtual function
    执行力
    目标、计划:下定决心 排除万难
    当断不断,必受其乱
  • 原文地址:https://www.cnblogs.com/zhaobao1830/p/9333524.html
Copyright © 2011-2022 走看看