接上文 上文我们实现了一个简单的AOP,但是其实还是存在问题的。 问题在哪里? 回到我们最开始的问题。我们希望的是,在我们的请求开始的时候调用loading,在我们请求结束的隐藏loading。我们以前的代码看起来没有问题。但是真的没有问题吗?实际上我们用这份代码做测试的时候我们就会发现问题所在了。因为异步的存在。 这里就不再探讨异步是什么了,我相信你能听懂我再说什么。
// 执行器 function actuator(obj){ if(obj){ if(typeof obj === 'function'){ obj() } if(obj instanceof Array){ obj.forEach(fn => { if(typeof fn === 'function'){ fn() } }); } } } function Action(actions){ return function(){ try{ // 执行before actuator(actions.before) // 执行 service actuator(actions.service) // 执行after actuator(actions.after) } catch(err){ actuator(actions.error) } } }在这个代码里面 我们没有去处理异步的东西。我们首先要做的,就是处理异步。给出解决方案 使用 async跟await
async function actuator (obj) { if (obj) { if (typeof obj === 'function') { await obj() } if (obj instanceof Array) { for (let fn of obj) { if (typeof fn === 'function') { await fn() } } } } } function Action (actions) { return async function () { try { // 执行before await actuator(actions.before) // 执行 service await actuator(actions.service) // 执行after await actuator(actions.after) } catch (err) { actions.error(err) } } }这样就能执行异步的函数了,我们的service的代码,如果是异步的,那么就会等待异步的代码执行结束之后,再执行after的代码了。
其次是在使用上的一些问题。 我们传入的是一个对象 defalutActionsObj
let defalutActionsObj={ before:[strategy.strategy1('before 执行')], service:[strategy.strategy2.bind({text:'this text'},'bind strategy2'),strategy.strategy2('service')], after:strategy.strategy3 } let action1=Action(defalutActionsObj) action1()这里存在的问题是,如果我们期望的是带参数的呢?比如我们loading显示的字 我们希望通过函数的参数传递进去。那么使用对象就不友好了
我们可以转而把actions变成一个函数
function operateAction (actions, params) { let defaultParams = { p1: '默认p1', p2: '默认p2', p3: '默认p3', } Object.assign(defaultParams, params) let obj = { before:[strategy.strategy1(defaultParams.p1)], service:actions, after:strategy.strategy3.bind(null,defaultParams.p3) } if (actions instanceof Function) { obj.service = actions } else if (actions instanceof Object) { obj = actions } return Object.assign({}, obj) } function awaitService() { return new Promise((resolve,reject)=>{ setTimeout(() => { resolve('3000') }, 3000); }) } let action2=Action(operateAction(async ()=>{ let r= await awaitService() console.log(r); },{ p1:'p1', p2:'p2', p3:'p3' })) action2()这样我们就可以很方便的进行调用了。
现在已经是一个可以用于实践中的解决方案了。但是他依旧不是很完美。这个就留到下一个章节再进行评价。为什么他还存在问题,以及一些,通用的东西。
