最近团队内部做了一个web app,用koa做服务端,一直对他中间件实现很感兴趣,对他的源码研究之后,写了一份简化版本的中间件实现。代码除了用到ES6的Generator和Promise,没有用到其他三方库,总共不到一百行,希望能帮助大家理解!
'use strict'; var middleware = []; //向数据库请求数据 var getDataPromise = new Promise(function(resolve,reject){ setTimeout(function(){ resolve({ data:'这就是数据' }); },1500) }); /** * session中间件 * @param next */ function* session(next){ console.log(1); yield next; console.log(2); } middleware.push(session); /** * logger中间件 */ function* logger(next){ console.log(3); yield next; console.log(4); } middleware.push(logger); /** * response中间件 */ function* response(){ console.log(5); console.log('请求数据库数据...'); let data = yield getDataPromise; console.log(data); console.log(6); } middleware.push(response); /** * 将中间件的遍历器函数转化为遍历器对象,并且将每一个遍历器对象指定为下一个遍历器对象的参数 * @param next * @returns {*} */ function* toGeneratorObject(next){ if (!next) next = function*(){}; var i = middleware.length; while (i--) { next = middleware[i].call(this, next); } return yield *next; } //第一个中间件的遍历器对象 var firstMiddleWareGenerator = toGeneratorObject(); /** * 将中间件的遍历器对象包装成一个Promise * @param gen * @returns {Promise} */ function wrapPromise(gen){ return new Promise(function(resolve,reject){ function onFullField (res){ var ret = gen.next(res); next(ret); } onFullField(); function next(ret){ var value = null; if(ret.done){ resolve(ret.value); return; } //假如是promise,不做任何处理 if(typeof ret.value.then == 'function'){ value = ret.value; }else { //假如不是,就包装成promise实例 value = wrapPromise(ret.value); } value.then(onFullField); } }); } wrapPromise(firstMiddleWareGenerator).then(function(){ console.log('执行完了'); });