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


思考题 下面的输出顺序是?
// 1. 导入koa包const Koa = require('koa')// 2. 实例化对象const app = new Koa()// 3. 编写中间件app.use((ctx, next) => {console.log(1)next()console.log(2)console.log('---------------')ctx.body = 'hello world'})app.use((ctx, next) => {console.log(3)next()console.log(4)})app.use((ctx)=>{console.log(5)})// 4. 监听端口, 启动服务app.listen(3000)console.log('server is running on http://localhost:3000')
洋葱圈模型
中间件函数队列,会在最后一个中间件或一个没有调用next的中间件那里停止 。koa官方文档上把外层的中间件称为"上游",内层的中间件为"下游" 。一般的中间件都会执行两次,调用next之前为第一次,调用next时把控制传递给下游的下一个中间件 。当下游不再有中间件或者没有执行next函数时,就将依次恢复上游中间件的行为,让上游中间件执行next之后的代码 从源代码看use
use(fn) {// 判断是否为函数if (typeof fn !== 'function') throw new TypeError('middleware must be a function!');// 判断是否为generator函数,并转化为generator函数if (isGeneratorFunction(fn)) {deprecate('Support for generators will be removed in v3. ' +'See the documentation for examples of how to convert old middleware ' +'https://github.com/koajs/koa/blob/master/docs/migration.md');fn = convert(fn);}// 调试DEBUG=koa* node app.jsdebug('use %s', fn._name || fn.name || '-');// 把中间件push进middlewarethis.middleware.push(fn);return this;}
函数
函数是es6 新增的一种异步编程的解决方案,语法和传统的函数完全不同; 函数的最大的特点就是可以交出函数的执行权(即暂停执行) 。
1)形式上: 函数是一个普通的函数,不过相对于普通函数多出了两个特征 。一是在关键字和函数明之间多了’*'号;二是函数内部使用了yield表达式,用于定义函数中的每个状态 。
2)语法上: 函数封装了多个内部状态(通过yield表达式定义内部状态) 。执行函数时会返回一个遍历器对象((迭代器)对象) 。也就是说,是遍历器对象生成函数,函数内部封装了多个状态 。通过返回的3)对象,可以依次遍历(调用next方法)函数的每个内部状态 。
3)调用上: 普通函数在调用之后会立即执行,而函数调用之后不会立即执行,而是会返回遍历器对象(对象) 。通过对象的next方法来遍历内部yield表达式定义的每一个状态 。
function *myGenerator() {yield 'Hello'yield 'world'return 'ending'}let MG = myGenerator()MG.next() // {value:'Hello',done:false}MG.next() // {value:'world',done:false}MG.next() // {value:'ending',done:true}MG.next() // {value:'undefined',done:false}
上面代码一共调用了四次next方法 。
第一次调用,函数开始执行,直到遇到第一个yield表达式为止 。next方法返回一个对象,它的value属性就是当前yield表达式的值hello,done属性的值false,表示遍历还没有结束 。
第二次调用,函数从上次yield表达式停下的地方,一直执行到下一个yield表达式 。next方法返回的对象的value属性就是当前yield表达式的值world,done属性的值false,表示遍历还没有结束 。
第三次调用,函数从上次yield表达式停下的地方,一直执行到语句(如果没有语句,就执行到函数结束) 。next方法返回的对象的value属性,就是紧跟在语句后面的表达式的值(如果没有语句,则value属性的值为),done属性的值true,表示遍历已经结束 。