城市直播房产教育博客汽车
投稿投诉
汽车报价
买车新车
博客专栏
专题精品
教育留学
高考读书
房产家居
彩票视频
直播黑猫
投资微博
城市上海
政务旅游

从浅入深了解Koa2源码

7月7日 月依兮投稿
  在前文我们介绍过什么是Koa2的基础简单回顾下什么是koa2NodeJS的web开发框架Koa可被视为nodejs的HTTP模块的抽象源码重点
  中间件机制
  洋葱模型
  compose源码结构
  Koa2的源码地址:https:github。comkoajskoa
  其中lib为其源码
  koa2源码
  可以看出,只有四个文件:application。js、context。js、request。js、response。jsapplication
  为入口文件,它继承了Emitter模块,Emitter模块是NodeJS原生的模块,简单来说,Emitter模块能实现事件监听和事件触发能力
  application1
  删掉注释,从整理看Application构造函数
  Application构造函数
  Application在其原型上提供了listen、toJSON、inspect、use、callback、handleRequest、createContext、onerror等八个方法,其中listen:提供HTTP服务use:中间件挂载callback:获取httpserver所需要的callback函数handleRequest:处理请求体createContext:构造ctx,合并node的req、res,构造Koa的参数ctxonerror:错误处理
  其他的先不要在意,我们再来看看构造器constructor
  Application的构造器
  晕,这都啥和啥,我们启动一个最简单的服务,看看实例constKoarequire(Koa)constappnewKoa()app。use((ctx){ctx。bodyhelloworld})app。listen(3000,(){console。log(3000请求成功)})console。dir(app)
  实例
  能看出来,我们的实例和构造器一一对应,
  打断点看原型
  断点
  哦了,除去非关键字段,我们只关注重点
  Koa的构造器上的this。middleware、this。context、this。request、this。response
  原型上有:listen、use、callback、handleRequest、createContext、onerror
  注:以下代码都是删除异常和非关键代码先看listen。。。listen(。。。args){constserverhttp。createServer(this。callback())returnserver。listen(。。。args)}。。。
  可以看出listen就是用http模块封装了一个http服务,重点是传入的this。callback()。好,我们现在就去看callback方法callbackcallback(){constfncompose(this。middleware)consthandleRequest(req,res){constctxthis。createContext(req,res)returnthis。handleRequest(ctx,fn)}returnhandleRequest}
  它包含了中间件的合并,上下文的处理,以及res的特殊处理中间件的合并
  使用了koacompose来合并中间件,这也是洋葱模型的关键,koacompose的源码地址:https:github。comkoajscompose。这代码已经三年没动了,稳的一逼functioncompose(middleware){returnfunction(context,next){letindex1returndispatch(0)functiondispatch(i){if(iindex)returnPromise。reject(newError(next()calledmultipletimes))indexiletfnmiddleware〔i〕if(imiddleware。length)fnnextif(!fn)returnPromise。resolve()try{returnPromise。resolve(fn(context,dispatch。bind(null,i1)))}catch(err){returnPromise。reject(err)}}}}
  一晃眼是看不明白的,我们需要先明白middleware是什么,即中间件数组,那它是怎么来的呢,构造器中有this。middleware,谁使用到了use方法
  我们先跳出去先看use方法useuse(fn){this。middleware。push(fn)returnthis}
  除去异常处理,关键是这两步,this。middleware是一个数组,第一步往this。middleware中push中间件;第二步返回this让其可以链式调用,当初本人被面试如何做promise的链式调用,懵逼脸,没想到在这里看到了
  回过头来看koacompose源码,设想一下这种场景。。。app。use(async(ctx,next){console。log(1);awaitnext();console。log(6);});app。use(async(ctx,next){console。log(2);awaitnext();console。log(5);});app。use(async(ctx,next){console。log(3);ctx。console。log(4);});。。。
  我们知道它的运行是123456
  它的this。middleware的构成是this。middleware〔async(ctx,next){console。log(1)awaitnext()console。log(6)},async(ctx,next){console。log(2)awaitnext()console。log(5)},async(ctx,next){console。log(3)ctx。bodyhelloworldconsole。log(4)},〕
  不要感到奇怪,函数也是对象之一,是对象就可以传值
  constfncompose(this。middleware)
  我们将其JavaScript化,其他不用改,只需要把最后一个函数改成async(ctx,next){console。log(3);ctx。console。log(helloworld);console。log(4);}
  测试compose
  测试compose2逐行解析koacompose
  这一段很重要,面试的时候常考,让你手写一个compose,淦它1。async(ctx,next){console。log(1);awaitnext();console。log(6);}中间件2。constfncompose(this。middleware)合并中间件3。fn()执行中间件functioncompose(middleware){returnfunction(context,next){letindex1;returndispatch(0);functiondispatch(i){if(iindex)returnPromise。reject(newError(next()calledmultipletimes),);letfnmiddleware〔i〕;if(imiddleware。length)if(!fn)returnPromise。resolve();try{returnPromise。resolve(fn(context,dispatch。bind(null,i1)));}catch(err){returnPromise。reject(err);}}};}
  执行constfncompose(this。middleware),即如下代码constfnfunction(context,next){letindex1returndispatch(0)functiondispatch(i){if(iindex)returnPromise。reject(newError(next()calledmultipletimes))indexiletfnmiddleware〔i〕if(imiddleware。length)fnnextif(!fn)returnPromise。resolve()try{returnPromise。resolve(fn(context,dispatch。bind(null,i1)))}catch(err){returnPromise。reject(err)}}}}
  执行fn(),即如下代码:constfnfunction(context,next){letindex1returndispatch(0)functiondispatch(i){if(iindex)returnPromise。reject(newError(next()calledmultipletimes))indexiindex0letfnmiddleware〔i〕fn为第一个中间件if(imiddleware。length)fnnext当弄到最后一个中间件时,最后一个中间件赋值为fnif(!fn)returnPromise。resolve()try{returnPromise。resolve(fn(context,dispatch。bind(null,i1)))返回一个Promise实例,执行递归执行dispatch(1)}catch(err){returnPromise。reject(err)}}}}
  也就是第一个中间件,要先等第二个中间件执行完才返回,第二个要等第三个执行完才返回,直到中间件执行执行完毕
  Promise。resolve就是个Promise实例,之所以使用Promise。resolve是为了解决异步,之所以使用Promise。resolve是为了解决异步
  抛去Promise。resolve,我们先看一下递归的使用,执行以下代码constfnfunction(){returndispatch(0);functiondispatch(i){if(i3)i;console。log(i);returndispatch(i);}};fn();1,2,3,4
  回过头来再看一次compose,代码类似于假设this。middleware〔fn1,fn2,fn3〕functionfn(context,next){if(imiddleware。length)fnnextfn3没有nextif(!fn)returnPromise。resolve()因为fn为空,执行这一行functiondispatch(0){returnPromise。resolve(fn(context,functiondispatch(1){returnPromise。resolve(fn(context,functiondispatch(2){returnPromise。resolve()}))}))}}}
  这种递归的方式类似执行栈,先进先出
  执行栈
  这里要多思考一下,递归的使用,对Promise。resolve不用太在意上下文的处理
  上下文的处理即调用了createContextcreateContext(req,res){constcontextObject。create(this。context)constrequest(context。requestObject。create(this。request))constresponse(context。responseObject。create(this。response))context。apprequest。appresponse。appthiscontext。reqrequest。reqresponse。reqreqcontext。resrequest。resresponse。resresrequest。ctxresponse。ctxcontextrequest。responseresponseresponse。requestrequestcontext。originalUrlrequest。originalUrlreq。urlcontext。state{}returncontext}
  传入原生的request和response,返回一个上下文context,代码很清晰,不解释res的特殊处理
  callback中是先执行this。createContext,拿到上下文后,再去执行handleRequest,先看代码:handleRequest(ctx,fnMiddleware){constresctx。resres。statusCode404constonerror(err)ctx。onerror(err)consthandleResponse()respond(ctx)onFinished(res,onerror)returnfnMiddleware(ctx)。then(handleResponse)。catch(onerror)}
  一切都清晰了constKoarequire(Koa);constappnewKoa();console。log(app,app);app。use((ctx,next){ctx。});app。listen(3000,(){console。log(3000请求成功);});
  这样一段代码,实例化后,获得了this。middleware、this。context、this。request、this。response四大将,你使用app。use()时,将其中的函数推到this。middleware。再使用app。listen()时,相当于起了一个HTTP服务,它合并了中间件,获取了上下文,并对res进行了特殊处理错误处理onerror(err){if(!(errinstanceofError))thrownewTypeError(util。format(nonerrorthrown:j,err))if(404err。statuserr。expose)returnif(this。silent)returnconstmsgerr。stackerr。toString()console。error()console。error(msg。replace(gm,))console。error()}context。js
  引入我眼帘的是两个东西1。constprotomodule。exports{inspect(){。。。},toJSON(){。。。},。。。}2。delegate(proto,response)。method(attachment)。access(status)。。。
  第一个可以理解为,constproto{inspect(){。。。}。。。},并且module。exports导出这个对象
  第二个可以这么看,delegate就是代理,这是为了方便开发者而设计的将内部对象response的属性,委托至暴露在外的proto上delegate(proto,response)。method(redirect)。method(vary)。access(status)。access(body)。getter(headerSent)。getter(writable);。。。
  而使用delegate(proto,response)。access(status)。。。,就是在context。js导出的文件,把proto。response上的各个参数都代理到proto上,那proto。response是什么?就是context。response,context。response哪来的?
  回顾一下,在createContext中createContext(req,res){constcontextObject。create(this。context)constrequest(context。requestObject。create(this。request))constresponse(context。responseObject。create(this。response))。。。}
  context。response有了,就明了了,context。responsethis。response,因为delegate,所以context。response上的参数代理到了context上了,举个例子ctx。header是ctx。request。header上代理的ctx。body是ctx。response。body上代理的request。js和response。js
  一个处理请求对象,一个处理返回对象,基本上是对原生req、res的简化处理,大量使用了ES6中的get和post语法
  大概就是这样,了解了这么多,怎么手写一个Koa2呢,请看下一篇手写Koa2参考资料KOA2框架原理解析和实现可能是目前最全的koa源码解析指南
投诉 评论 转载

宝宝起名起个姓与名顺理成章的好名字,每一个都好听又绝妙文章宛如乐章,千字是文,百字是文,三字是文,两字是文。没错,姓名就是一篇文章。所以,斟名酌字也要注重姓与名之间的兼容性,做到海纳百川,有容乃大。一言以蔽之,就是将姓包容在名当中……书评未来500年迈向太空的生命工程之旅书名:《未来500年:迈向太空的生命工程之旅》作者:ChristopherE。Mason(克里斯托弗梅森)NASA首席科学家出版时间:20220401出版社:……从浅入深了解Koa2源码在前文我们介绍过什么是Koa2的基础简单回顾下什么是koa2NodeJS的web开发框架Koa可被视为nodejs的HTTP模块的抽象源码重点中间件机制洋葱模型……演宋运萍被夸,演顾清俞被骂,童瑶为何口碑越来越差?童瑶很美,都市丽人。演技也说得过去,比同龄女星好太多,为何口碑却越来越差?《心居》开播,多少人想看到海清与童瑶两女主的对手戏。但是童瑶的演技频频被质疑,甚至有网友评……荨麻疹,晚上痒?或是血虚风燥!介绍五味中药帮您止痒冬去春来,万物复苏,百花齐放,极易容易过敏,引起皮肤瘙痒,比如荨麻疹。小陈经常受荨麻疹困扰,特别是春秋两季,身上就会起疹,颜色淡红,不是很痒,但是到下午或者晚上就难受,医……30张图看世界,巴西女用涂料当衣服尽显高级,菲律宾至美悬崖餐世界那么大,好想去看看!今天的内容将带你漫游一个从未见过的奇妙世界,看了让人感觉姿势大涨,话不多说,让我们马上开始吧。直布罗陀机场,是世界上条件最恶劣的机场之一,这里不仅……造车之际,如果活不下去了,华为做鞋袜都是世界级品牌近日,余承东亲自发布了AITO问界M7,这也是华为造车的一个重要跨越。刚刚,华为声明!在发布会后接受采访时,余承东也是感慨良多,特意谈了华为如何打造世界级品牌。华为被告上……新海诚言叶之庭当中那些现实取景的画面被誉为现代映像叙事诗的剧场动画《言叶之庭》是日本导演新海诚在2013年的新作。剧中以雨为主题,对雨景深入细致的刻画加上完美的色彩搭配,惊艳一时。毫不夸张的说,作品里的每一帧画面……女子奶茶里吃出活虫,以为是白芝麻,店家食品卫生没有问题奶茶是很多人都喜欢喝的饮料,尤其是年轻人更喜欢喝。一般出去逛街或者去旅游,看到奶茶店都会去买一杯。喝奶茶似乎已经成为了年轻人的一种时尚,大街小巷都开满了奶茶店,而且生意都特别火……胃好不好,从什么地方能看出来,中医辩证调理胃病你吃了吗?这是国人口中较为常用的一句问候语,最初,反映的是人们在历经艰难岁月时相互之间一种实实在在的关切,而进一步讲,则可以看作是人们对身体健康的相互提醒,为什么这么说呢?……五月很洒脱的个性说说一、带不走四季的风,就卷走一路的风景;遇不到心动的人,就孤身潇洒走四方。二、钱是治疗情绪的最佳良药,简单粗暴又好用。三、命运从不偏坦投机侥幸者,也不负努力踏实人,因……NBA官方晒G6汤数据16西决41分ampampamp11三直播吧6月17日讯上午9点,总决赛G6勇士客场对阵凯尔特人。赛前NBA官方INS晒出了克莱在季后赛G6的高光时刻,具体如下:2016年西决VS雷霆G6,41分,投进……
质量安全工程专业就业前景每天早上起床,多做这4个步骤,预防心梗脑梗,中老年人要知道习惯影响成败小米发布4款新机,依然是性价比王者,这回销量口碑不用愁了妈妈的爱拍照造句用拍照造句大全慢性咽炎偏方治好我们的慢性咽炎夫妻睡姿揭示关系亲密程度床上的姿势决定你们的关系世界杯谁能代表绿茶一瞥一笑一沧海一瓶1499元的飞天茅台包含了多少税金?计算结果令人意外市骨干教师申报的述职报告
我的人生规划5。1澳门游(2)付出努力后收获成功的励志故事甜宠剧天花板来了!首日开播冲上飙升榜第1,一口气能看24集国风美少男刘宇,为何创造营排名会掉到第四?贺李昉(体育)2023年全国马术三项赛锦标赛乔仑巴特卫冕个人赛冠军用什么软件查微信聊天记录(微信怎样查看所有聊天记录)老人出游如何制定旅游计划玫瑰蜂蜜水的功效与作用有什么成功者必备的秘籍班级剩饭菜超重取消奖学金评选

友情链接:中准网聚热点快百科快传网快生活快软网快好知文好找江西南阳嘉兴昆明铜陵滨州广东西昌常德梅州兰州阳江运城金华广西萍乡大理重庆诸暨泉州安庆南充武汉辽宁