中间件实现比较我们在很多地方都用到了中间件的概念。我理解的中间件就是在代码执行过程中插入一些中间过程。1redux中的中间件是普通功能的中间件。functions的嵌套执行/**执行中间件得到中间件的返回函数数组chain,然后使用compose方法生成执行chain方法的嵌套dispatch函数,中间件形式为(getState,dispatch)=>下一个=>动作=>{下一个(动作);}*/exportdefaultfunctionapplyMiddleware(...middlewares){return(createStore)=>(reducer,preloadedState,enhancer)=>{varstore=createStore(reducer,preloadedState,enhancer)vardispatch=store.dispatchvarchain=[]varmiddlewareAPI={getState:store.getState,dispatch:(action)=>dispatch(action)}chain=middlewares.map(middleware=>middleware(middlewareAPI))dispatch=compose(...chain)(store.dispatch)/**store.dispatch是firstnext和lastware的next(...args)=>{returnware0(ware1(ware2(last(...args))))}dispatch=ware0(ware1(ware2(last(...args))))所以中间件传入next后返回的函数就是我们需要的函数形式,比如dispatch需要的函数形式就是传递一个action*/return{...store,dispatch}}}/**reduceRight从数组的右到左执行。初始参数是最后一个函数接受dispatch,得到一个action=>{dispatch(action);}形式的函数。composef作为参数的形式是next=>action=>{}最终形式是(...args)=>{returnfuncs0(funcs1(funcs2(last(...args))))}*/export默认函数compose(...funcs){if(funcs.length===0){returnarg=>arg}if(funcs.length===1){returnfuncs[0]}constlast=funcs[funcs.长度-1]constrest=funcs。slice(0,-1)return(...args)=>rest.reduceRight((composed,f)=>f(composed),last(...args))}模拟这个过程functionfunc1(next){returnfunction(){console.log("func1start");下一个();console.log("func1结束");}}functionfunc2(next){returnfunction(){console.log("func2start");下一个();console.log("func2结束");}}functionfunc3(next){returnfunction(){console.log("func3start");下一个();console.log("func3结束");}functionApp(){this.middlewares=[]}App.prototype.use=function(middleware){this.middlewares.push(middleware)}App.prototype.exec=function(data){//funclistfunc1(func2(func3(dispatch)))letfunclist=this.middlewares.reduceRight(function(generate,next){returnnext(generate)},dispatch)funclist()}functiondispatch(){console.log('dispatch')}letapp=newApp();app.use(func1)app.use(func2)app.使用(func3)app.exec('exec');模拟直接中间件流程,express中间件原理类似这个原理functionfunc4(next){console.log("func4start");下一个();console.log("func4end");}functionfunc5(next){console.log("func5start");下一个();console.log("func5end");}functionfunc6(next){console.log("func6start");下一个();console.log("func6end");}letmiddlewareList=[func4,func5,func6];functionexec(){letresult=middlewareList.reduceRight(function(first,second){返回函数(name){second(first)}},function(){console.log('lastnext')})result()}exec();2koa2中间件koa2中的中间件也是一个async函数使用use方法添加加到数组中,使用的时候重点是compose,如何组中间件,然后返回Promisemodule.exports=classApplicationextendsEmitter{constructor(){this.middleware=[];}listen(){debug('listen');constserver=http.createServer(this.callback());返回server.listen.apply(服务器,参数);}use(fn){if(typeoffn!=='function')thrownewTypeError('middlewaremustbeafunction!');if(isGeneratorFunction(fn)){deprecate('对生成器的支持将在v3中删除。'+'请参阅文档以获取有关如何转换旧中间件的示例'+'https://github.com/koajs/koa/blob/master/docs/migration.md');fn=转换(fn);}debug('使用%s',fn._name||fn.name||'-');这个.middleware.push(fn);归还这个;}callback(){constfn=compose(this.middleware);if(!this.listeners('error').length)this.on('error',this.onerror);consthandleRequest=(req,res)=>{res.statusCode=404;constctx=this.createContext(req,res);constonerror=err=>ctx.onerror(err);consthandleResponse=()=>respond(ctx);onFinished(res,onerror);返回fn(ctx).then(handleResponse).catch(onerror);};返回句柄请求;}};//////koa-compose这里从第一个中间件开始执行,传递给下一个中间件,也就是执行下一个中间件的方法,它也可以返回一个值。这里async函数的返回值是promise,可以等待promise,等待执行,达到写代码同步的效果。returnfunction(context,next){//最后调用的中间件#letindex=-1returndispatch(0)//从第一个中间件开始,async函数的返回值也是promise。functiondispatch(i){if(i<=index)returnPromise.reject(newError('next()被多次调用'))index=iletfn=middleware[i]if(i===middleware.length)fn=nextif(!fn)returnPromise.resolve()try{returnPromise.resolve(fn(context,functionnext(){returndispatch(i+1)}))}catch(err){returnPromise.reject(err)}}}3koa1的中间件koa1的中间件是一个生成器函数,关键是中间件的compose方法不一样。koa2中使用的async函数可以直接执行并返回promise,而koa1中的generator函数不能直接Execute,所以koa1中的compose是通过generator生成的迭代器,所以next是一个迭代器,而koa2中的next是一个方法,并且然后生成一个大型生成器函数,该函数使用co模块执行。co模块的执行是先对next获取的值进行promise,然后执行promise,在promise的then和catch中继续调用迭代器的next方法执行迭代器。app.callback=function(){if(this.experimental){console.error('ExperimentalES7AsyncFunctionsupportisdeprecated.PleaselookintoKoav2asthemiddlewaresignaturehaschanged.')}//经过compose和co的包装得到一个承诺varfn=this.experimental?compose_es7(this.middleware):co.wrap(compose(this.middleware));变种自我=这个;返回函数handleRequest(req,res){res.statusCode=404;varctx=self.createContext(req,res);onFinished(res,ctx.onerror);fn.call(ctx).then(functionhandleResponse(){respond.call(ctx);}).catch(ctx.onerror);}};/*****************koa-compose*****************/functioncompose(middleware){返回函数*(下一个){如果(!下一个)next=noop();vari=middleware.length;while(i--){next=middleware[i].call(this,next);}返回收益*下一个;}}function*noop(){}/*****************co模块******************/functionco(gen){varctx=this;可变参数=切片。call(arguments,1)//我们将所有内容包装在一个promise中以避免promise链,//这会导致内存泄漏错误。//参见https://github.com/tj/co/issues/180returnnewPromise(function(resolve,reject){if(typeofgen==='function')gen=gen.apply(ctx,args);if(!gen||typeofgen.next!=='function')returnresolve(gen);onFulfilled();functiononFulfilled(res){varret;try{//继续执行跟踪器ret=gen.next(res);}catch(e){returnreject(e);}next(ret);}functiononRejected(err){varret;try{ret=gen.throw(err);}catch(e){返回reject(e);}next(ret);}functionnext(ret){//如果代理器执行完成if(ret.done)returnresolve(ret.value);//promise化valuevarvalue=toPromise.call(ctx,ret.value);//执行valueif(value&&isPromise(value))returnvalue.then(onFulfilled,onRejected);returnonRejected(newTypeError('你只能生成一个函数、promise、生成器、数组或对象,'+'但传递了以下对象:"'+String(ret.value)+'"'));}});}如果觉得有所收获,欢迎关注微信公众号前端良文每周分享前端开发干货知识点
