基础http请求
const http=require("http");
const app=http.createServer((req,res)=>{
res.writeHead(200);
res.end("Hello");
})
app.listen(3000,()=>{
console.log("listen to 3001")
})
针对http基础请求简单封装
Application.js:
const http=require('http');
class Application{
constructor(){
this.callback=''
}
use(callback){
this.callback=callback
}
listen(...args){
let app=http.createServer((req,res)=>{
this.callback(req,res);
})
app.listen(...args)
}
}
module.exports=Application
test.js:
const Qow=require('./Application');
const app=new Qow();
app.use((req,res)=>{
res.writeHead(200);
res.end("Hello");
})
app.listen(3001,()=>{
console.log("listen to 3001")
})
js的getter和setter
const zq={
_name:"zq",
get name(){
return this._name
},
set name(name){
this._name=name
}
}
console.log(zq.name)
zq.name="zq1"
console.log(zq.name)
说明:类似于java的get,set,其实_name还可以使用,
只不过规范定义为下划线标志为私有,最好别使用。
封装ctx的阶段性代码
Application.js:
const http = require("http")
let response = {
get body() {
return this._body;
},
set body(val) {
this._body = val
}
}
let request = {
get url() {
return this.req.url;
}
}
let context = {
get body() {
return this.response.body;
},
set body(val) {
this.response.body = val;
},
get url() {
return this.request.url;
}
}
class Application {
constructor() {
this.context = context
this.request = request
this.response = response
}
use(callback) {
this.callback = callback;
}
listen(...args) {
//作用:async作用是因为内部的callback可能是异步操作
let app = http.createServer(async (req, res) => {
let ctx = this.createCtx(req, res)
await this.callback(ctx);
//在callbak内部,也就是test.js中ctx.body已经被重新赋值,所以下面可以直接使用
ctx.res.end(ctx.body)
})
app.listen(...args)
}
createCtx(req, res) {
let ctx = Object.create(this.context);
ctx.request = Object.create(this.request);
ctx.response = Object.create(this.response)
//作用:就是类似koa的ctx直接可使用一些属性,同时request/response也都可以使用
ctx.req = ctx.request.req = req;
ctx.res = ctx.response.res = res;
return ctx;
}
}
module.exports = Application
test.js:
const Qow=require('./demo/a');
const app=new Qow();
app.use(async ctx=>{
ctx.body='Hello'
})
app.listen(3001,()=>{
console.log("listen to 3001")
})
嵌套调用
function add(x,y) {
return x+y
}
function double(z){
return z*2
}
const result=double(add(1,2))
console.log(result)//6
同步中间件模拟
function add(x,y) {
return x+y
}
function double(z){
return z*2
}
const middlewares=[add,double];
let len=middlewares.length;
function compose(midds){
return (...args)=>{
//初始化默认执行第一个函数(后期就是中间件)
let res=midds[0](...args)
for (let i = 1; i < len; i++) {
res=midds[i](res)
}
return res;
}
}
const fn=compose(middlewares)
const result=fn(1,2)
console.log(result)//6
说明:该逻辑和上面的js模块效果相同都是串联执行,把上一次结果当成下一次的参数
中间件模拟
//异步的测试
async function fn1(next){
console.log('fn1');
await next()
console.log('end fn1');
}
async function fn2(next){
console.log('fn2');
await delay()
await next()
console.log('end fn2');
}
function fn3(next){
console.log('fn3');
}
function delay(){
return new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve()
},2000)
})
}
function compose(middlewares){
return function () {
return dispatch(0)
function dispatch(i){
let fn=middlewares[i];
if(!fn){
return Promise.resolve()
}
return Promise.resolve(fn(function next() {
return dispatch(i+1)
}))
}
}
}
const middlewares=[fn1,fn2,fn3];
const final=compose(middlewares);
final()
输出:输出 fn1 fn2 延时两秒 fn3 end fn2 end fn1
精简版本Koa实现和测试
Application.js:
const http = require("http")
let response = {
get body() {
return this._body;
},
set body(val) {
this._body = val
}
}
let request = {
get url() {
return this.req.url;
}
}
let context = {
get body() {
return this.response.body;
},
set body(val) {
this.response.body = val;
},
get url() {
return this.request.url;
}
}
class Application {
constructor() {
this.context = context
this.request = request
this.response = response
this.middlewares=[]
}
use(callback) {
this.middlewares.push(callback)
// this.callback = callback;
}
listen(...args) {
let app = http.createServer(async (req, res) => {
let ctx = this.createCtx(req, res)
const fn=this.compose(this.middlewares)
await fn(ctx);
ctx.res.end(ctx.body)
})
app.listen(...args)
}
compose(middlewares){
return function (context) {
return dispatch(0)
function dispatch(i){
let fn=middlewares[i];
if(!fn){
return Promise.resolve()
}
return Promise.resolve(fn(context,function next() {
return dispatch(i+1)
}))
}
}
}
createCtx(req, res) {
let ctx = Object.create(this.context);
ctx.request = Object.create(this.request);
ctx.response = Object.create(this.response);
ctx.req = ctx.request.req = req;
ctx.res = ctx.response.res = res;
return ctx;
}
}
module.exports = Application
test.js:
const Qow=require('./demo/a');
const app=new Qow();
app.use(async (ctx,next)=>{
ctx.body='1'
await next()
ctx.body+='5'
})
app.use(async (ctx,next)=>{
ctx.body+='2'
await next()
ctx.body+='4'
})
app.use(async ctx=>{
ctx.body+='3'
})
app.listen(3001,()=>{
console.log("listen to 3001")
})
网页输出:12345
next浅析
use(fn) {
// ...
this.middleware.push(fn);
return this;
}
// ...
callback() {
const fn = compose(this.middleware);
// ..
}
function compose (middleware) {
return function (context, next) {
// last called middleware #
let index = -1
return dispatch(0)
function dispatch (i) {
if (i <= index) return Promise.reject(new Error('next() called multiple times'))
index = i
let fn = middleware[i]
if (i === middleware.length) fn = next
if (!fn) return Promise.resolve()
try {
return Promise.resolve(fn(context, dispatch.bind(null, i + 1)));
} catch (err) {
return Promise.reject(err)
}
}
}
}
// 执行第一个中间件 p1-1
Promise.resolve(function(context, next){
console.log('executing first mw');
// 执行第二个中间件 p2-1
await Promise.resolve(function(context, next){
console.log('executing second mw');
// 执行第三个中间件 p3-1
await Promise(function(context, next){
console.log('executing third mw');
await next()
// 回过来执行 p3-2
console.log('executing third mw2');
}());
// 回过来执行 p2-2
console.log('executing second mw2');
})
// 回过来执行 p1-2
console.log('executing first mw2');
}());
执行顺序可以理解为以下的样子:
// 执行第一个中间件 p1-1
first = (ctx, next) => {
console.log('executing first mw');
next();
// next() 即执行了第二个中间件 p2-1
second = (ctx, next) => {
console.log('executing second mw');
next();
// next() 即执行了第三个中间件 p3-1
third = (ctx, next) => {
console.log('executing third mw');
next(); // 没有下一个中间件了, 开始执行剩余代码
// 回过来执行 p3-2
console.log('executing third mw2');
}
// 回过来执行 p2-2
console.log('executing second mw2');
}
// 回过来执行 p1-2
console.log('executing first mw2');
}