洋葱模型是一种很经典的程序设计思路:
function compose (middleware) { // some code}复制代码
它能接受一个函数数组,然后返回一个新的函数,达到这样的效果:
let middleware = []middleware.push((next) => { console.log(0) next() console.log(3)})middleware.push((next) => { console.log(1) next() console.log(1.1)})middleware.push(() => { console.log(2)})let fn = compose(middleware)fn()/*0121.13*/复制代码
当我们尝试执行fn的时候,它会按照顺序调用之前函数数组中的函数,并且给每一个小函数传递一个参数: next函数。
如果在小函数中执行next,就会调用这个函数的下一个函数,如果没有执行next,程序就不会往下走。所以你可以看到上面的打印顺序。
但是问题来了,我们怎么写这个compose函数?
首先, 这个compose函数肯定会返回一个大的函数嘛,所以:
function compose (middleware) { return function () { }}复制代码
然后返回的函数是fn,如果我们尝试执行fn, fn将会尝试执行middleware[0],同时就想我们之前说的,它会给这个小函数传入一个next函数
function compose (middleware) { return function () { let f1 = middleware[0] f1(function next(){ }) }}复制代码
然后这个next函数有开关的功能,如果我们执行next函数,next函数就会调用数组中下一个函数,所以
function compose (middleware) { return function () { let f1 = middleware[0] f1(function next(){ let f2 = middleware[1] f2(function next(){ ... }) }) }}复制代码
然后。。。这是递归!为了让上面的更优雅,我们可以这样写
function compose (middleware) { return function () { dispatch(0) function dispatch (i) { const fn = middleware[i] if (!fn) return null fn(function next () { dispatch(i + 1) }) } }}复制代码
通过一个dispatch来优雅的实现递增。
然后我们还希望这个函数支持异步函数:
function compose (middleware) { return async function () { await dispatch(0) function async dispatch (i) { const fn = middleware[i] if (!fn) return null await fn(function next () { dispatch(i + 1) }) } }}复制代码
最后一步,允许用户传递参数
function compose (middleware) { return async function () { let args = arguments await dispatch(0) function async dispatch (i) { const fn = middleware[i] if (!fn) return null await fn(function next () { dispatch(i + 1) }, ...args) } }}复制代码
参考:
源代码: