「这是我参与2022首次更文挑战的第3天,活动详情查看:2022首次更文挑战」。
手撕koa,从零掌握koa的实现原理(3)
往期更文
前言
- 回顾昨天的内容,我们先初步实现了
listen方法,listen方法的主要作用是使用http模块开启一个服务,最后我们导出了Application。 koa/koa/lib/application.jsconst http = require('http') const EventEmitter = require('events') class Application extends EventEmitter { constructor(){ super() } handleRequest = (req, res) => { res.statusCode = 200 //因为我们响应的是中文,所以需要设置一下content-type,否则浏览器会显示乱码 res.setHeader('content-type','text/plain;charset=utf-8') res.end('自己实现的Koa') } listen(){ const server = http.createServer(this.handleRequest) server.listen(...arguments) } } module.exports = Application
如何让每个应用的上下文对象分离?
- 每个
koa的实例上会有一个上下文对象context,那么koa在创建单独的应用的时候是如何让每个应用的上下文对象context分离的呢?带着这个问题我们来往下走。 -
- 创建三个文件
koa/koa/lib/context用于扩展我们的koa上下文对象。koa/koa/lib/request用于扩展我们的koa上下文对象中的request。koa/koa/lib/response用于扩展我们的koa上下文对象中的response。
-
- 每个文件先简单声明三个对象,然后导出。
koa/koa/lib/context.jsconst context = {} module.exports = contextkoa/koa/lib/request.jsconst request = {} module.exports = requestkoa/koa/lib/response.jsconst response = {} module.exports = response
-
- 在我们
new Application的时候我们应该给应用的实例创建context request response三个对象,来改造我们的Application吧。
koa/koa/lib/application.jsconst http = require('http') const EventEmitter = require('events') const context = require('./context'); const request = require('./request'); const response = require('./response'); class Application extends EventEmitter { constructor(){ super() this.context = context this.request = request this.response = response } handleRequest = (req, res) => { res.statusCode = 200 res.setHeader('content-type','text/plain;charset=utf-8') res.end('自己实现的Koa') } listen(){ const server = http.createServer(this.handleRequest) server.listen(...arguments) } } module.exports = Application
- 在我们
- 需要注意的是我们的构造函数
constructor中这样写可以吗?答案当然是否定的,这样写的话,我们在每次this.context = context this.request = request this.response = responsenew Koa()的时候拿到的上下文就都是同一个,我们需要的是每次new Koa()的时候,都单独创建一个单独的上下文对象,即每个应用实例的上下文对象应该都是分离的。 - 那我们就需要重新改造我们的
Application了,像下面这样,我们需要使用Object.create()方法,每次都创建一个新的对象,让新对象的__proto__指向我们扩展的context上下文对象,从而实现继承,这样我们就可以让每个应用实例的上下文对象分离了,但是他们又可以共享我们扩展的公共的属性和方法。const http = require('http') const EventEmitter = require('events') const context = require('./context'); const request = require('./request'); const response = require('./response'); class Application extends EventEmitter { constructor(){ super() this.context = Object.create(context) this.request = Object.create(request) this.response = Object.create(response) } handleRequest = (req, res) => { res.statusCode = 200 res.setHeader('content-type','text/plain;charset=utf-8') res.end('自己实现的Koa') } listen(){ const server = http.createServer(this.handleRequest) server.listen(...arguments) } } module.exports = Application
最后需要强调的
我们学习源码,不只是简单的看懂作者的怎么写的,怎么去实现的,代码层面的东西固然是重要的,但是最重要的还是,我们要吸收作者背后优秀、巧妙的思想,这些优秀巧妙的思想,才是我们进步的强大源泉,在代码的枯燥中,方能苦中作乐,对作者的构思巧妙惊为天人。