generator探幽(1)--koa中间件机制浅析

本文详细解析了Node.js环境下Middleware的概念及其在koa框架中的具体实现方式,通过实例展示了如何利用Generator和Iterator实现中间件的串联与执行流程。重点介绍了koa框架中的compose函数是如何将多个中间件串联并按顺序执行,最终达到处理HTTP请求的效果。

本系列旨在通过对co,koa等库源码的研究,进而理解generator在异步编程中的重大作用(ps:所有代码请在node --harmony或者iojs环境中运行)

koa中间件的形式

相信用过koa的小伙伴一定很熟悉下面这段代码

var app = require('koa')(),
    router = require('koa-router')();

app.use(function *(next){
    console.log(1);
    yield next;
    console.log(5);
});
app.use(function *(next){
    console.log(2);
    yield next;
    console.log(4);
});
app.use(function *(){
    console.log(3);
});

app.listen(3000);

当一个请求到达的时候,控制台会依次输出1 2 3 4 5,这就是koa中强大的middleware特性,撇开koa本身,我们来扯扯middleware这东西是怎么实现的

yield *iterator

不熟悉generatoriterator的小伙伴可以先看下阮一峰先生编写的《ES6入门》的generator函数这一节
假设你已经熟悉了generator和iterator,现在我们来看一段代码

function *m1(){
    console.log(1);
    yield *m2Iterator;
    console.log(3);
}

function *m2(){
    console.log(2);
}
var m1Iterator = m1(),
    m2Iterator = m2();

m1Iterator.next();//

上面代码运行后,控制台会依次输出1 2 3,这是因为在m1函数内部,yield后面跟的是一个iterator
m1Iterator.next()调用后,m1函数开始执行。
m1运行到yield *m2Iterator时,不会暂停,而是直接跳进m2函数执行m2函数内的代码。
由于m2函数中没有yield,因此会一直执行完m2函数中的代码,并返回至m1函数中执行yield *m2Iterator后面的代码。

middleware中间件的雏形

理解了上面的过程后,我们接着看下面这段代码

function *m1(){
    console.log(1);
    yield *m2();
    console.log(5);
}

function *m2(){
    console.log(2);
    yield *m3();
    console.log(4);
}

function *m3(){
    console.log(3);
}

m1().next(); //控制台依次输出1 2 3 4 5

是不是形式跟我们一开始看到的koa的中间件有点接近了?

compose

composekoa里用来实现中间件机制的模块
compose函数最关键的一段代码

while(i--){
    next = middleware[i].call(this, next);
}
yield *next;

这段代码把middleware中传进来的generator数组逆序取出并依次执行,每次执行的时候把上次generator执行返回的iterator当作参数传进去,所有generator执行完之后,调用第一个iterator
因此,在generator中间件函数中,其实yield后面跟的是个iterator,即yield *next
下面用一个例子来说明这个过程

function *m1(next){
    console.log(1);
    yield *next;
    console.log(5);
}

function *m2(next){
    console.log(2);
    yield *next;
    console.log(4);
}

function *m3(){
    console.log(3);
}

var gen = compose([m1, m2, m3]),
    it = gen();
//compose([m1, m2, m3])()可以想象成它做了这么一些事(伪代码):
//1 var it3 = m3();
//2 var it2 = m2(it3);
//3 var it1 = m1(it2);
//4 gen = function(){
//          yield *it1;  
//        }

it.next(); //控制台依次输出1 2 3 4 5

现在就很像koa的中间件的写法了。唯一的差别是koa中使用的是yeild next而我们这里用的是yield *next
其实在koayeild nextyeild *next效果是等价的,这主要得益于co库,我们以后再来好好扯扯这小玩意~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值