共计 2799 个字符,预计需要花费 7 分钟才能阅读完成。
这篇文章探讨 js 的洋葱模型以它的实现原理,洋葱模型顾名思义,指的是办法的执行像洋葱一样,一层一层往里执行,直到中心点后,再一层一层往外进去。
下面的图片取自 koa 中间件的流程管制图,react-redux
的中间件也采纳了一样的原理。
let fn1 = (next) => {console.log(1)
next()
console.log(2)
}
let fn2 = (next) => {console.log(3)
next()
console.log(4)
}
let fn3 = (next) => {console.log(5)
next()
console.log(6)
}
const middlewares = [fn1, fn2, fn3];
compose(middlewares)();
/* result:1
3
5
6
4
2
*/
合并后的 middlewares
数组,通过 compose
解决打印进去的后果是:1、3、5、6、4、2,咱们能够想到 compose
函数回的函数外面是怎么执行的:
+----------------------------------------------------------------------------------+
| |
| fn1 |
| |
| +-----------------------------------------------------------+ |
| | | |
| | fn2 | |
| | | |
| | +---------------------------------+ | |
| | | | | |
| action | action | fn3 | action | action |
| 1 | 3 | | 4 | 2 |
| | | action action | | |
| | | 5 6 | | |
| | | | | |
+----------------------------------------------------------------------------------------------->
| | | | | |
| | | | | |
| | +---------------------------------+ | |
| +-----------------------------------------------------------+ |
+----------------------------------------------------------------------------------+
那么咱们就开始编写 compose
函数,首先它必须返回的是一个函数,并且每次函数执行,都须要将下一个函数作为参数传给它,这样才可能让办法一层层的执行上来,直到最外面一层:
function compose(middlewarw) {return function(args){dispatch(0);
function dispatch(index){let fn = middlewarw[index] || args;
if(typeof fn !== "function") return;
let next = ()=> dispatch(index+1);
fn(next);
}
}
};
当然咱们也心愿碰上异步函数,也能失常的执行:
function asyncFn() {return new Promise((resolve, reject) => {setTimeout(() => {console.log("delay...");
resolve();}, 1000);
});
}
let fn1 = async (next) => {console.log(1)
await next()
console.log(2)
}
let fn2 = async (next) => {console.log(3)
await asyncFn();
await next()
console.log(4)
}
let fn3 = async (next) => {console.log(5)
await next()
console.log(6)
};
function compose(middlewarw) {return function (args) {dispatch(0);
function dispatch(index) {let fn = middlewarw[index] || args;
if (typeof fn !== "function") return Promise.resolve();
let next = () => dispatch(index + 1);
// 给执行函数增加返回胜利的 Promise.resolve
return Promise.resolve(fn(next))
}
}
};
compose([fn1,fn2,fn3])();
react-redux 的中间件实现
react-redux
的中间件是这样实现 compose
函数的:
function compose(middlewarw) {return middlewarw.reduce((total, next) => (...args) => total(next(...args)));
}
react-redux
中间件执行的函数很不好了解,不过咱们能够拆开它外面的函数来一步步剖析:
let fn1 = (next) => {return ()=>{console.log(1)
next()
console.log(2)
}
}
let fn2 = (next) => {return ()=>{console.log(3)
next()
console.log(4)
}
}
let fn3 = (next) => {return ()=>{console.log(5)
next()
console.log(6)
}
}
let dispatch = compose([fn1,fn2,fn3])(()=> console.log("dispatch"));
dispatch();
middlewarw
通过 reduce
叠加,每次都将上一次的后果返回给下一个函数作参数:
// 第 1 次 reduce 的返回值,变成 total 传递到下一次
arg => fn1(() => fn2(arg));
// 第 2 次 reduce 的返回值,持续作为下一次的 total
arg => (arg => fn1(() => fn2(arg)))(() => fn3(arg));
或者将 compose
转成比拟好了解的函数迭代模式:
function compose(middlewarw) {return function(cb) {function dispatch(index){let fn = middlewarw[index];
let next = ()=>dispatch(index+1); // 下一次的函数执行
// 如果不存在下一个函数了,拿到传参外面的函数执行,这里须要保障传参是一个函数,对应的是 redux 外面的 dispatch 参数
fn ? fn(next)() : cb()
}
// 最终返回一个函数
return ()=> dispatch(0);
}
};
正文完
发表至: javascript
2020-08-12