• 简易步骤控制器


    简介

    不少复杂函数中都存在一个问题,逻辑步骤或分支较多,很多时候我们都采用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);
      }
    }
    
  • 相关阅读:
    excel秒数据转换成年月日时分秒格式
    5-整合swagger2
    JavaSE项目练习:图书管理系统
    SpringCloud - Spring Cloud Alibaba 之 SkyWalking 分布式链路跟踪;跨多服务追踪,集成日志(十五)
    node 第十八天 中间件express-session实现会话密钥
    80、【backtrader基金策略】实现上证50ETF和创业板ETF轮动交易策略(2022-07-17更新)
    如何在Java、C、Ruby语言中使用Newscatcher API
    vue:基础:生命周期
    uni-app:js二维数组与对象数组之间的转换
    Day4 数据分析 Excel图表【零基础】
  • 原文地址:https://blog.csdn.net/spring5530/article/details/127100055