likes
comments
collection
share

关于如何将单函数屎山代码行数由120+优化到30+前言 原因:测试提了一个BUG,而当我去解决这个BUG的时,定位到了一

作者站长头像
站长
· 阅读数 20

前言

原因:测试提了一个BUG,而当我去解决这个BUG的时,定位到了一个函数 源码如下

function judgeAllEmployee(status: number) {
  let flag = false;
  let count = 0;
  this.dispatchList = [];
  if (this.noDispatch) {
    for (
      let i = 0;
      i <
      (status === 1 ? this.dataList.length : this.transferDataList.length);
      i++
    ) {
      let item = status === 1 ? this.dataList[i] : this.transferDataList[i];
     
      if (status === 2) {
        this.dispatchList[i] = {
          isa_order_plan_id: item.isa_order_plan_id,
          responsible_employee_id: item.responsible_employee_id,
          assistant_id: item.assistant_id,
          updateEnable: item.updateEnable,
        };
      } else {
        this.dispatchList[i] = {
          isa_order_plan_id: item.isa_order_plan_id,
          responsible_employee_id: item.responsible_employee_id,
          assistant_id: item.assistant_id,
        };
      }
      if (!!item.children && item.children.length > 0) {
        this.dispatchList[i].children = [];
        for (let j = 0; j < item.children.length; j++) {
          let data = item.children[j];
          
          if (data.responsible_employee_id != 0) {
            count++;
          }
          if (status === 2) {
            this.dispatchList[i].children[j] = {
              isa_order_plan_id: data.isa_order_plan_id,
              responsible_employee_id: data.responsible_employee_id,
              assistant_id: data.assistant_id,
              updateEnable: data.updateEnable,
            };
          } else {
            this.dispatchList[i].children[j] = {
              isa_order_plan_id: data.isa_order_plan_id,
              responsible_employee_id: data.responsible_employee_id,
              assistant_id: data.assistant_id,
            };
          }
        }
      } else {
        if (item.responsible_employee_id != 0) {
          count++;
        }
      }
    }
    console.log("已编辑数量" + count);
    if (count > 0) {
      flag = true;
    } else {
      flag = false;
    }
  } else {
    for (let i = 0; i < this.dataList.length; i++) {
      let item = this.dataList[i];

      if (status === 2) {
        this.dispatchList[i] = {
          isa_order_plan_id: item.isa_order_plan_id,
          responsible_employee_id: item.responsible_employee_id,
          assistant_id: item.assistant_id,
          updateEnable: item.updateEnable,
        };
      } else {
        this.dispatchList[i] = {
          isa_order_plan_id: item.isa_order_plan_id,
          responsible_employee_id: item.responsible_employee_id,
          assistant_id: item.assistant_id,
        };
      }
      if (!!item.children && item.children.length > 0) {
        this.dispatchList[i].children = [];
        for (let j = 0; j < item.children.length; j++) {
          let data = item.children[j];
          if (
            data.responsible_employee_id != 0 &&
            (!data.distributed_by || data.distributed_by == 0)
          ) {
            count++;
          }

          if (status === 2) {
            this.dispatchList[i].children[j] = {
              isa_order_plan_id: data.isa_order_plan_id,
              responsible_employee_id: data.responsible_employee_id,
              assistant_id: data.assistant_id,
              updateEnable: data.updateEnable,
            };
          } else {
            this.dispatchList[i].children[j] = {
              isa_order_plan_id: data.isa_order_plan_id,
              responsible_employee_id: data.responsible_employee_id,
              assistant_id: data.assistant_id,
            };
          }
        }
      } else {
        if (
          item.responsible_employee_id != 0 &&
          (!item.distributed_by || item.distributed_by == 0)
        ) {
          count++;
        }
      }
    }
    console.log("已编辑数量" + count);
    if (count > 0) {
      flag = true;
    } else {
      flag = false;
    }
  }
  return flag;
}

该函数的作者早已不见人影,而这个BUG涉及到这个函数的处理,我愣是看了10分钟。觉得这段代码最大的特色就是人和代码有一个能跑的就行,现在人跑了tips:我一直本着有需求才执行,倘若这块内容没有问题,想必我肯定是不会去动的。因为轻易的变更原来的内容,是大忌,可能隔两个月,八百里开外客户现场出现了问题,然后追溯一番和你有关系,那就是好心办坏事了。

目标

  1. 注意代码优化而不是业务优化,保证业务没有变更,仅对代码进行优化
  2. 代码优化后,再对问题进行定位

第一版

先进行无关业务并且保证不影响原来的功能情况下,进行函数解耦 观察发现屎山中针对xxxx进行了多次相同的处理

this.dispatchList[i].children[j] = {
 isa_order_plan_id: data.isa_order_plan_id,
 responsible_employee_id: data.responsible_employee_id,
 assistant_id: data.assistant_id,
};

而这块的处理也很容易理解,就是根据status,是否增加updateEnable字段 那么我们剥离出一个公共函数getDispatchItem处理

function getDispatchItem(item, status) {
  return {
    isa_order_plan_id: item.isa_order_plan_id,
    responsible_employee_id: item.responsible_employee_id,
    assistant_id: item.assistant_id,
    ...(status === 2 && { updateEnable: item.updateEnable })
  };
}

然后将这个函数在屎山中替换达到 函数行数由126->82

function judgeAllEmployee(status: number) {
  let flag = false;
  let count = 0;
  this.dispatchList = [];
  if (this.noDispatch) {
    for (
      let i = 0;
      i <
      (status === 1 ? this.dataList.length : this.transferDataList.length);
      i++
    ) {
      let item = status === 1 ? this.dataList[i] : this.transferDataList[i];
      this.dispatchList[i] =  getDispatchItem(item, status)
      if (!!item.children && item.children.length > 0) {
        this.dispatchList[i].children = [];
        for (let j = 0; j < item.children.length; j++) {
          let data = item.children[j];

          if (data.responsible_employee_id != 0) {
            count++;
          }
          this.dispatchList[i].children[j] = getDispatchItem(data, status)
        }
      } else {
        if (item.responsible_employee_id != 0) {
          count++;
        }
      }
    }
    console.log("已编辑数量" + count);
    if (count > 0) {
      flag = true;
    } else {
      flag = false;
    }
  } else {
    for (let i = 0; i < this.dataList.length; i++) {
      let item = this.dataList[i];
      this.dispatchList[i] = getDispatchItem(item, status)

      if (!!item.children && item.children.length > 0) {
        this.dispatchList[i].children = [];
        for (let j = 0; j < item.children.length; j++) {
          let data = item.children[j];
          if (
            data.responsible_employee_id != 0 &&
            (!data.distributed_by || data.distributed_by == 0)
          ) {
            count++;
          }

          this.dispatchList[i].children[j] = getDispatchItem(data, status)

        }
      } else {
        if (
          item.responsible_employee_id != 0 &&
          (!item.distributed_by || item.distributed_by == 0)
        ) {
          count++;
        }
      }
    }
    console.log("已编辑数量" + count);
    if (count > 0) {
      flag = true;
    } else {
      flag = false;
    }
  }
  return flag;
}
function getDispatchItem(item, status) {
  return {
    isa_order_plan_id: item.isa_order_plan_id,
    responsible_employee_id: item.responsible_employee_id,
    assistant_id: item.assistant_id,
    ...(status === 2 && { updateEnable: item.updateEnable })
  };
}

第二版

发现“屎山”中存在两处类似的代码

      if (!!item.children && item.children.length > 0) {
        this.dispatchList[i].children = [];
        for (let j = 0; j < item.children.length; j++) {
          let data = item.children[j];

          if (data.responsible_employee_id != 0) {
            count++;
          }
          this.dispatchList[i].children[j] = getDispatchItem(data, status);
        }
      } else {
        if (item.responsible_employee_id != 0) {
          count++;
        }
      }
      if (!!item.children && item.children.length > 0) {
        this.dispatchList[i].children = [];
        for (let j = 0; j < item.children.length; j++) {
          let data = item.children[j];
          if (
            data.responsible_employee_id != 0 &&
            (!data.distributed_by || data.distributed_by == 0)
          ) {
            count++;
          }

          this.dispatchList[i].children[j] = getDispatchItem(data, status);
        }
      } else {
        if (
          item.responsible_employee_id != 0 &&
          (!item.distributed_by || item.distributed_by == 0)
        ) {
          count++;
        }
      }

这块代码的作用是判断子项是否处于派工状态 针对这段代码进行提取公共函数并优化 因为这个函数中大量使用到了临时变量count、this.dispatchList剥离出来的话,入参会很多所以结合在函数内部进行修改 修改完如下,82->56

function judgeAllEmployee(status: number) {
  let flag = false;
  let count = 0;
  this.dispatchList = [];
  const processChildren = (parent, parentIndex) => {
    if (!!parent.children && parent.children.length > 0) {
      this.dispatchList[parentIndex].children = parent.children.map((child, childIndex) => {
        if (child.responsible_employee_id != 0) count++;
        return this.getDispatchItem(child, status);
      });
    } else if (parent.responsible_employee_id != 0 && !parent.distributed_by) {
      count++;
    }
  };
  if (this.noDispatch) {
    for (
      let i = 0;
      i <
      (status === 1 ? this.dataList.length : this.transferDataList.length);
      i++
    ) {
      let item = status === 1 ? this.dataList[i] : this.transferDataList[i];
      this.dispatchList[i] =  getDispatchItem(item, status)
      processChildren(item, i)

    }
    console.log("已编辑数量" + count);
    if (count > 0) {
      flag = true;
    } else {
      flag = false;
    }
  } else {
    for (let i = 0; i < this.dataList.length; i++) {
      let item = this.dataList[i];
      this.dispatchList[i] = getDispatchItem(item, status)
      processChildren(item, i)
    }
    console.log("已编辑数量" + count);
    if (count > 0) {
      flag = true;
    } else {
      flag = false;
    }
  }
  return flag;
}
function getDispatchItem(item, status) {
  return {
    isa_order_plan_id: item.isa_order_plan_id,
    responsible_employee_id: item.responsible_employee_id,
    assistant_id: item.assistant_id,
    ...(status === 2 && { updateEnable: item.updateEnable })
  };
}

第三版(最终版)

现在针对代码复用已经更改好了,再仔细看一下细节的内容

  1. 发现flagcount的冲突。(变量作用相同,重复声明)
  2. 大量使用for循环,而不是forEach;(尽量使用更简洁的语法)
  3. 关于循环的数组,要根据noDispatch&&status进行判断(判断冗余) 那么直接优化为
const list = status === 1 ? this.dataList : this.transferDataList;

最终版,由最开始的126->30+

judgeAllEmployee(status) {
  let count = 0;
  this.dispatchList = [];
  const list = status === 1 ? this.dataList : this.transferDataList;
  const processChildren = (parent, parentIndex) => {
    if (!!parent.children && parent.children.length > 0) {
      this.dispatchList[parentIndex].children = parent.children.map((child, childIndex) => {
        if (child.responsible_employee_id != 0) count++;
        return this.getDispatchItem(child, status);
      });
    } else if (parent.responsible_employee_id != 0 && !parent.distributed_by) {
      count++;
    }
  };
  if (this.noDispatch) {
    list.forEach((item, index) => {
      this.dispatchList[index] = this.getDispatchItem(item, status);
      processChildren(item, index);
    });
  } else {
    this.dataList.forEach((item, index) => {
      this.dispatchList[index] = this.getDispatchItem(item, status);
      processChildren(item, index);
    });
  }
  console.log("已编辑数量: " + count);
  return count > 0;
}
getDispatchItem(item, status) {
  return {
    isa_order_plan_id: item.isa_order_plan_id,
    responsible_employee_id: item.responsible_employee_id,
    assistant_id: item.assistant_id,
    ...(status === 2 && { updateEnable: item.updateEnable })
  };
}

后续优化点

当前基于不更改原函数的逻辑情况下,已经优化完成,但仍有继续优化的点。

  1. 这个函数并没有执行单一原则,关于这点还可以继续优化,根据这个函数名称可以判断作者的本意应该是判断状态,而不是组装数据。
  2. 在函数内部直接赋值全局变量this.dispatchList的数据,倘若这个数据出现问题,这个定位将十分痛苦。
  3. 关于注释,因为避免业务泄漏,我就全删掉了(你要认真读,也能理解)

总结

所幸这只是涉及到一个函数的更改,更多情况下,倘若业务足够复杂,那简直不敢想象。针对这块“屎山”优化也是因为只是单个函数,我还能够熟悉这块业务功能。所以当真的遇到更复杂的情况下,还是得思考一下。 而关于代码优化的思路,更变相于Code Review。

转载自:https://juejin.cn/post/7418895124527153171
评论
请登录