简易步骤控制器

简介

不少复杂函数中都存在一个问题,逻辑步骤或分支较多,很多时候我们都采用if else/Promise等来处理,而有些场景我们不得不额外把一部分逻辑封装成一个函数待以重用。
这些问题便会使得整个函数变得更复杂和难以维护,借助Promise.then思路我们可以模拟一个步骤控制器step来解决此问题

调用示例:

step(next => {
  // some condition
  next()
})
.step(next => {
  // do something
})

step函数体可实现异步/同步效果,这取决于next的执行时机.

准备

首先,step是一个函数,并且可以反复的调用自身:

function step(excuter) {
  if(!excuter || typeof excuter !== 'function') {
    return false
  }

  // do something...
  
  return {
    step(excuter) {
      return this
    }
  }
}

在函数执行后返回一个对象,包含step方法,step方法执行后又返回这个对象本身,从而达到重复调用

生成步骤队列

在每一步执行时,把任务本身放入任务队列中,供下一步使用

function step(excuter) {
  if(!excuter || typeof excuter !== 'function') {
    return false
  }
  
  const steps = []
  
  return {
    step(excuter) {
      steps.push(excuter)
      return this
    }
  }
}

执行步骤

执行步骤:第一步通过微任务异步执行,后面的步骤可同步可异步,取决于上一步执行完成的时机.
注意:由于生成步骤队列需要优先生成,故此第一步只能设为异步执行.

function step(excuter) {
  if(!excuter || typeof excuter !== 'function') {
    return false
  }
  
  const steps = []
  const next = (data) => {
    if(!steps.length) {
      return false
    }

    const stepExceter = steps.shift()
    stepExceter(next, context)
  }

  window.queueMicrotask(() => {
    excuter(next, context)
  })
  
  return {
    step(excuter) {
      steps.push(excuter)
      return this
    }
  }
}

步骤数据

每个步骤都是一个独立函数,不利于变量传递,因此在执行的时候常常需要储存或取数.

const context = {
  data: new Map(),
  prevData: null,
}

context.setData = (key, value) => {
  if(context.data.has(key)) {
    throw new Error(`key: ${key}, 已存在!`)
  }

  context.data.set(key, value)
}

context.getData = (key) => {
  return context.data.get(key)
}

完整代码

// util.function.js

export function step(excuter) {
  if(!excuter || typeof excuter !== 'function') {
    return false
  }
  
  const context = {
    data: new Map(),
    prevData: null,
  }
  const steps = []
  const next = (data) => {
    if(!steps.length) {
      return false
    }

    context.prevData = data

    const stepExceter = steps.shift()
    stepExceter(next, context)
  }

  context.setData = (key, value) => {
    if(context.data.has(key)) {
      throw new Error(`key: ${key}, 已存在!`)
    }

    context.data.set(key, value)
  }

  context.getData = (key) => {
    return context.data.get(key)
  }

  window.queueMicrotask(() => {
    excuter(next, context)
  })
  
  return {
    step(excuter) {
      steps.push(excuter)
      return this
    }
  }
}

export default {
  step
}

调用样例

runAction(item, tab) {
  const {action,validateInput} = item
  const constFunction = [
    'copyResult', 'clearResult', 'clearAll'
  ]
  
  try {
    if(constFunction.includes(action)) {
      return this[action](tab)
    }

    step(next => {
      if(!action) {
        throw new Error('该动作不是一个函数,请检查配置.')
      }
      next()
    })
    .step(next => {
      // 需要校验
      if(validateInput && tab.inputs.length > 1) {
        this.$refs[tab.name][0].validate().then(() => {
          next()
        })
      } else {
        next()
      }
    })
    .step(next => {
      const params = tab.inputs.map(x => {
        let value = tab.inputModel[x.name]
        return x.transform === 'json' ? JSON.parse(value) : value
      })

      let result = action.apply(this, params)
      if (result instanceof Promise) {
        result.then(res => {
          next(res)
        })
      } else {
        next(result)
      }
    })
    .step((next, ctx) => {
      this.updateOutputResult(tab.output, ctx.prevData)
    })

  } catch (error) {
    ElMessage.error(error.message);
  }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值