摘要:的中間件的中間件是函數(shù),所以關(guān)鍵點(diǎn)是對(duì)中間件的方法不同,中利用的函數(shù)可以直接執(zhí)行返回,而中函數(shù)不能直接執(zhí)行,所以中的是把生成的迭代器進(jìn)行傳遞,所以是迭代器,中是方法,然后生成一個(gè)大的函數(shù),利用模塊進(jìn)行執(zhí)行。
中間件的實(shí)現(xiàn)對(duì)比
我們?cè)诤芏嗟胤蕉加玫搅酥虚g件的概念,我理解的中間件就是代碼執(zhí)行過(guò)程中插入一些中間過(guò)程。
1 redux中的中間件就是普通函數(shù)的中間件,函數(shù)的嵌套執(zhí)行
/** 執(zhí)行中間件,得到中間件的返回函數(shù)數(shù)組chain,然后利用compose方法,生成嵌套的執(zhí)行chain 方法的包裝dispatch函數(shù), 中間件的形式是 (getState, dispatch)=> next => action => { next(action); } */ export default function applyMiddleware(...middlewares) { return (createStore) => (reducer, preloadedState, enhancer) => { var store = createStore(reducer, preloadedState, enhancer) var dispatch = store.dispatch var chain = [] var middlewareAPI = { getState: store.getState, dispatch: (action) => dispatch(action) } chain = middlewares.map(middleware => middleware(middlewareAPI)) dispatch = compose(...chain)(store.dispatch) /** store.dispatch 就是第一個(gè)next 是last ware的next (...args) => { return ware0(ware1(ware2(last(...args)))) } dispatch = ware0(ware1(ware2(last(...args)))) 所以中間件中next傳入后返回的函數(shù)就是我們需要的函數(shù)形式, 例如dispatch 需要的函數(shù)形式是 傳一個(gè)action */ return { ...store, dispatch } } } /** reduceRight是數(shù)組的從右至左執(zhí)行, 初始的參數(shù)是最后一個(gè)函數(shù)接受dispatch, 的到的一個(gè)action=>{ dispatch(action); } 形式的函數(shù),作為參數(shù)composed f的形式是 next=>action=>{ } 最終形成的就是 (...args) => { return funcs0(funcs1(funcs2(last(...args)))) } */ export default function compose(...funcs) { if (funcs.length === 0) { return arg => arg } if (funcs.length === 1) { return funcs[0] } const last = funcs[funcs.length - 1] const rest = funcs.slice(0, -1) return (...args) => rest.reduceRight((composed, f) => f(composed), last(...args)) }
模擬這個(gè)過(guò)程
function func1 (next) { return function () { console.log("func1 start"); next(); console.log("func1 end"); } } function func2 (next) { return function () { console.log("func2 start"); next(); console.log("func2 end"); } } function func3 (next) { return function () { console.log("func3 start"); next(); console.log("func3 end"); } } function App () { this.middlewares = [] } App.prototype.use = function (middleware) { this.middlewares.push(middleware) } App.prototype.exec = function (data) { //funclist func1(func2(func3(dispatch))) let funclist = this.middlewares.reduceRight(function (generate, next) { return next(generate) }, dispatch) funclist() } function dispatch () { console.log("dispatch") } let app = new App(); app.use(func1) app.use(func2) app.use(func3) app.exec("exec");
模擬直接的中間件過(guò)程,express的中間件類似這個(gè)原理
function func4 (next) { console.log("func4 start"); next(); console.log("func4 end"); } function func5 (next) { console.log("func5 start"); next(); console.log("func5 end"); } function func6 (next) { console.log("func6 start"); next(); console.log("func6 end"); } let middlewareList = [func4, func5, func6]; function exec() { let result = middlewareList.reduceRight(function (first, second){ return function (name) { second(first) } },function(){console.log("last next")}) result() } exec();2 koa2的中間件
koa2中的中間件是async函數(shù)
也是用use方法添加到數(shù)組中,使用的時(shí)候重點(diǎn)是compose,如何組裝中間件,然后返回Promise module.exports = class Application extends Emitter { constructor() { this.middleware = []; } listen() { debug("listen"); const server = http.createServer(this.callback()); return server.listen.apply(server, arguments); } use(fn) { if (typeof fn !== "function") throw new TypeError("middleware must be a function!"); 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("use %s", fn._name || fn.name || "-"); this.middleware.push(fn); return this; } callback() { const fn = compose(this.middleware); if (!this.listeners("error").length) this.on("error", this.onerror); const handleRequest = (req, res) => { res.statusCode = 404; const ctx = this.createContext(req, res); const onerror = err => ctx.onerror(err); const handleResponse = () => respond(ctx); onFinished(res, onerror); return fn(ctx).then(handleResponse).catch(onerror); }; return handleRequest; } }; //////koa-compose 這里從第一個(gè)中間件開(kāi)始執(zhí)行,傳給中間件的next,就是執(zhí)行下一個(gè)中間件的方法,并且還可以返回值,這里利用了async函數(shù)的返回值是promise,并且可以await promise, 等待執(zhí)行,達(dá)到了寫代碼和同步類似的效果。 return function (context, next) { // last called middleware # let index = -1 return dispatch(0) / //從第一個(gè)中間件開(kāi)始執(zhí)行,async函數(shù)的返回值也是promise。 function dispatch (i) { if (i <= index) return Promise.reject(new Error("next() called multiple times")) index = i let fn = middleware[i] if (i === middleware.length) fn = next if (!fn) return Promise.resolve() try { return Promise.resolve(fn(context, function next () { return dispatch(i + 1) })) } catch (err) { return Promise.reject(err) } } }3 koa1的中間件
koa1的中間件是generator函數(shù),所以關(guān)鍵點(diǎn)是對(duì)中間件的compose方法不同,koa2中利用的async函數(shù)可以直接執(zhí)行返回promise,而koa1中g(shù)enerator函數(shù)不能直接執(zhí)行,所以
koa1中的compose是把generator生成的迭代器進(jìn)行傳遞,所以next是迭代器,koa2中next是方法,然后生成一個(gè)大的generator函數(shù),利用co模塊進(jìn)行執(zhí)行。
co模塊的執(zhí)行,是對(duì)next拿到的value先進(jìn)行promise化,然后再執(zhí)行promise,在promise的then和catch中繼續(xù)調(diào)用迭代器的next方法,執(zhí)行迭代器。
app.callback = function(){ if (this.experimental) { console.error("Experimental ES7 Async Function support is deprecated. Please look into Koa v2 as the middleware signature has changed.") } //經(jīng)過(guò)compose和co的wrap得到一個(gè)promise var fn = this.experimental ? compose_es7(this.middleware) : co.wrap(compose(this.middleware)); var self = this; return function handleRequest(req, res){ res.statusCode = 404; var ctx = self.createContext(req, res); onFinished(res, ctx.onerror); fn.call(ctx).then(function handleResponse() { respond.call(ctx); }).catch(ctx.onerror); } }; /*****************koa-compose*****************/ function compose(middleware){ return function *(next){ if (!next) next = noop(); var i = middleware.length; while (i--) { next = middleware[i].call(this, next); } return yield *next; } } function *noop(){} /*****************co模塊*****************/ function co(gen) { var ctx = this; var args = slice.call(arguments, 1) // we wrap everything in a promise to avoid promise chaining, // which leads to memory leak errors. // see https://github.com/tj/co/issues/180 return new Promise(function(resolve, reject) { if (typeof gen === "function") gen = gen.apply(ctx, args); if (!gen || typeof gen.next !== "function") return resolve(gen); onFulfilled(); function onFulfilled(res) { var ret; try { //繼續(xù)執(zhí)行迭代器 ret = gen.next(res); } catch (e) { return reject(e); } next(ret); } function onRejected(err) { var ret; try { ret = gen.throw(err); } catch (e) { return reject(e); } next(ret); } function next(ret) { //如果迭代器執(zhí)行完畢 if (ret.done) return resolve(ret.value); //promise化value var value = toPromise.call(ctx, ret.value); //執(zhí)行value if (value && isPromise(value)) return value.then(onFulfilled, onRejected); return onRejected(new TypeError("You may only yield a function, promise, generator, array, or object, " + "but the following object was passed: "" + String(ret.value) + """)); } }); }
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/82922.html
摘要:使用承諾和異步功能來(lái)擺脫回調(diào)地獄的應(yīng)用程序,并簡(jiǎn)化錯(cuò)誤處理。它暴露了自己的和對(duì)象,而不是的和對(duì)象。因此,可被視為的模塊的抽象,其中是的應(yīng)用程序框架。這使得中間件對(duì)于整個(gè)堆棧而言不僅僅是最終應(yīng)用程序代碼,而且更易于書(shū)寫,并更不容易出錯(cuò)。 Koa 與 Express 此系列文章的應(yīng)用示例已發(fā)布于 GitHub: koa-docs-Zh-CN. 可以 Fork 幫助改進(jìn)或 Star 關(guān)注更新...
作者簡(jiǎn)介 藍(lán)寅,開(kāi)源分布式中間件DBLE項(xiàng)目負(fù)責(zé)人;持續(xù)專注于數(shù)據(jù)庫(kù)方面的技術(shù), 始終在一線從事開(kāi)發(fā);對(duì)數(shù)據(jù)復(fù)制,讀寫分離,分庫(kù)分表的有深入的理解與實(shí)踐。 問(wèn)題起因: 用benchmarksql_for_mysql對(duì)原生MyCat-1.6.1和DBLE-2.17.07版做性能測(cè)試對(duì)比,發(fā)現(xiàn)DBLE性能只到原生版MyCat的70%左右。 問(wèn)題分析過(guò)程: 分析過(guò)程主要有以下內(nèi)容:包括現(xiàn)象,收集數(shù)據(jù),分...
閱讀 841·2021-11-16 11:56
閱讀 1654·2021-11-16 11:45
閱讀 3109·2021-10-08 10:13
閱讀 4094·2021-09-22 15:27
閱讀 727·2019-08-30 11:03
閱讀 643·2019-08-30 10:56
閱讀 946·2019-08-29 15:18
閱讀 1737·2019-08-29 14:05