手摸手学会node框架之一——koa 傻瓜式小白教程( 三 )


第四次调用,此时函数已经运行完毕,next方法返回对象的value属性为,done属性为true 。以后再调用next方法,返回的都是这个值 。
调用函数,返回一个遍历器对象,代表函数的内部指针 。以后,每次调用遍历器对象的next方法,就会返回一个有着value和done两个属性的对象 。value属性表示当前的内部状态的值,是yield表达式后面那个表达式的值;done属性是一个布尔值,表示是否遍历结束 。koa-源代码
从源代码观察洋葱模型的原理
'use strict'/*** Expose compositor.*/module.exports = compose/*** Compose `middleware` returning* a fully valid middleware comprised* of all those which are passed.** @param {Array} middleware* @return {Function}* @api public*/function compose (middleware) {// 判断接收的中间件是否为数组if (!Array.isArray(middleware)) throw new TypeError('Middleware stack must be an array!')for (const fn of middleware) {// 判断是否为函数if (typeof fn !== 'function') throw new TypeError('Middleware must be composed of functions!')}/*** @param {Object} context* @return {Promise}* @api public*/// 返回匿名函数,该函数接收两个参数return function (context, next) {// last called middleware #// 初始下标为-1,记录执行的中间件的索引let index = -1// 从第一个中间件并开始递归执行return dispatch(0) function dispatch (i) {// 这里是保证同个中间件中一个next()不被调用多次调用 // 当iindex,则该中间件并未执行,记录索引index = i// 根据下标取出中间件let fn = middleware[i]// 当i已经是数组的length了,说明中间件函数都执行结束,即已经到了洋葱最中心if (i === middleware.length) fn = nextif (!fn) return Promise.resolve()try {// 若数组下标并未到达最后一位,且存在当前中间件函数则执行当前函数并传入 dispatch(i + 1),就可看出是数组中的下一个中间件了,此时作为 next 传入了中间件函数中;// 也就是说我们写中间件时,已经默认注入了 ctx 与 下次执行的封装函数 next,也是因为如此我们在 koa 的中间件中才可以非常方便的判断什么时候进入下一个中间件去执行的洋葱结构,并且一定要执行 next() 否则数组将在此中断,因为这里是 Function.prototype.bind(),bind()方法会创建一个新函数,称为绑定函数.当调用这个绑定函数时,绑定函数会以创建它时传入 bind()方法的第一个参数作为 this,传入 bind()方法的第二个以及以后的参数加上绑定函数运行时本身的参数按照顺序作为原函数的参数来调用原函数.// 需注意的是 bind 时指向 null 也是为了以防在执行过程中你有什么骚操作改变了指向,那就不好了// 在不断的 Promise.resolve 中去实现递归 dispatch 函数,最终实现顺序控制执行所有中间件函数return Promise.resolve(fn(context, dispatch.bind(null, i + 1)));} catch (err) {return Promise.reject(err)}}}}

手摸手学会node框架之一——koa 傻瓜式小白教程

文章插图
四、路由 1、什么是路由
app.use((ctx) => {if (ctx.url == '/') {ctx.body = '这是主页'} else if (ctx.url == '/users') {if (ctx.method == 'GET') {ctx.body = '这是用户列表页'} else if (ctx.method == 'POST') {ctx.body = '创建用户'} else {ctx.status = 405 // 不支持的请求方法}} else {ctx.status = 404}})
2、使用koa- 1)安装
npm i koa-router或npm i @koa/router
2)使用
// 一. 导入koaconst Koa = require('koa')// 二. 实例化对象const app = new Koa()// 三. 导入koa-router, 实例化路由对象const Router = require('koa-router')const router = new Router()router.get('/', (ctx) => {ctx.body = '这是主页'})router.get('/users', (ctx) => {ctx.body = '这是用户页'})router.post('/users', (ctx) => {ctx.body = '创建用户页'})// 四. 注册路由中间件// userRouter.routes() 加载路由规则// userRouter.allowedMethods() 对于没有实现和没有使用的请求方式做出正确的响应app.use(router.routes())app.use(router.allowedMethods())// 五. 启动服务app.listen(3000, () => {console.log('server is running on http://localhost:3000')})