【分享】代码优化过程

阅读次数 408

简要说明: 代码主要用途是通过文件api服务访问远端内的某个工作表与融合表内的数据表进行比较,并把工作表内的最新数据同步更新到融合表内的数据表。该代码主要思路来自官方示例7。 优化前以下代码执行一轮需要500m+时间 每次只能跑30行左右,经常出错。
优化后执行一轮只需要10m左右时间,大大提高了执行效率。供大家参考

优化前代码:

function syncMainSheetToOthers(mainSh, keyField, mainToSyncFields, toSyncFields) {

  const recordsMap = new Map()

  const colEnd = mainSh.UsedRange.ColumnEnd
  //const rowEnd = mainSh.UsedRange.RowEnd

  const rowTitle = mainSh.Rows(3)
 
  for (let k = 1; k < colEnd; k++) {
    if (rowTitle.Columns(k).Text == keyField) {
      keyCol = k
      break
    }
  }
  console.log(keyCol) //查询唯一值所对应列号
  let titleRow=mainSh.Rows(3)
  for (let i = startRow; i < endRow + 1; i++) { //第四行开始有数据
     const start_time = new Date();
     console.log('开始执行循环:正在执行第'+i + '行' )

    const records = {}
   
    let row=mainSh.Rows(i)
    const xuke = row.Columns(keyCol).Text
    records[keyField] = xuke
    for (let j = 1; j < colEnd; j++) {
      
      const val = row.Columns(j).Text
      for (let m = 0; m < mainToSyncFields.length; m++) {
        if (mainToSyncFields[m] == titleRow.Columns(j).Text) {
          if (mainToSyncFields[m] == "发证日期") { //特殊处理日期
            if (!isDateFormate(val)) {
              records[toSyncFields[m]] = ""
            } else {
              records[toSyncFields[m]] = parseDate(val)
              //console.log(parseDate(val)+ '  '+xuke)
            }
          } else if (mainToSyncFields[m] == "截止日期") {
            if (!isDateFormate(val)) {
              records[toSyncFields[m]] = ""
            } else {
              records[toSyncFields[m]] = parseDate(val)
            }
          } else {
            records[toSyncFields[m]] = val
          }

        }

      }
    }
    if (recordsMap[xuke]) {
      console.error('有重复的记录', xuke)
    }

    recordsMap.set(xuke, records)
    console.log('执行完毕第 '+ i + '行')
      console.log(new Date() - start_time, 'ms');
  }

  // //返回新增记录

  // otherRecords = syncSheet(qySht, recordsMap, {
  //   keyField,
  //   mainToSyncFields,
  //   toSyncFields,
  // })
  // const myOtherRecords = []
  // otherRecords.forEach((value, key, map) => {
  //   myOtherRecords.push(value)
  // })
  // myOtherRecords.splice(0, 1) //删除第一个元素-表头

  // if (myOtherRecords.length > 0) {
  //   const result = qySht.Record.CreateRecords({
  //     SheetId: qySht.Id,
  //     Records: myOtherRecords.map(item => ({
  //       fields: item,
  //     })),
  //   })
  //   relateXiaqu(result)
  // }
}

image.png 优化后代码:

// 同步主表数据到其他表
function syncMainSheetToOthers(mainSh, keyField, mainToSyncFields, toSyncFields) {

  const recordsMap = new Map()

  const colEnd = mainSh.UsedRange.ColumnEnd
  //const rowEnd = mainSh.UsedRange.RowEnd

  const titleRow = mainSh.Rows(3)
  console.log('zhixing keycol')
  const indexObj = {}  //把所有 表头名:对应序号放入对象里
  for (let k = 1; k < colEnd; k++) {
    const title = titleRow.Columns(k).Text
    if (!indexObj[title]) {
      indexObj[title] = k
    }
  }
  const keyCol = indexObj[keyField]
  console.log(keyCol) //查询唯一值所对应列号

  for (let i = startRow; i < endRow + 1; i++) { //第四行开始有数据
    const start_time = new Date();
    console.log('开始执行循环:正在执行第' + i + '行')

    const records = {}

    let row = mainSh.Rows(i)
    const xuke = row.Columns(keyCol).Text
    console.log(xuke)
    records[keyField] = xuke

    for (let m = 0; m < mainToSyncFields.length; m++) {
      const val = row.Columns(indexObj[mainToSyncFields[m]]).Text//先赋值
      if (mainToSyncFields[m] == "发证日期") { //特殊处理日期
        if (!isDateFormate(val)) {
          records[toSyncFields[m]] = ""
        } else {
          records[toSyncFields[m]] = parseDate(val)
          
        }
      } else if (mainToSyncFields[m] == "截止日期") {
        if (!isDateFormate(val)) {
          records[toSyncFields[m]] = ""
        } else {
          records[toSyncFields[m]] = parseDate(val)
        }
      } else {
        records[toSyncFields[m]] = val
      }

    }

    if (recordsMap[xuke]) {
      console.error('有重复的记录', xuke)
    }

    recordsMap.set(xuke, records)
    console.log('执行完毕第 ' + i + '行')
    console.log(new Date() - start_time, 'ms');
  }

  //返回新增记录

  otherRecords = syncSheet(qySht, recordsMap, {
    keyField,
    mainToSyncFields,
    toSyncFields,
  })
  const myOtherRecords = []
  otherRecords.forEach((value, key, map) => {
    myOtherRecords.push(value)
  })

  // myOtherRecords.splice(0, 1) //删除第一个元素-表头

  if (myOtherRecords.length > 0) {
    const result = qySht.Record.CreateRecords({
      SheetId: qySht.Id,
      Records: myOtherRecords.map(item => ({
        fields: item,
      })),
    })
 
    relateXiaqu(result)
  }
}

image.png

优化要点 1、嵌套循环能少用就少用,能不用就不用,优化前用的三层嵌套循环,优化后只用了2层循环,上面代码中我先把所有列头名称及列号提前存储到indexObj对象内,在循环内直接调用indexObj对象,这样可以减少一层for循环,大大提高程序效率 2、重复使用的变量,第一次先存到临时变量,循环里直接使用临时变量
3、循环内尽量少访问工作表,如 sheet.Rows(i).Columns(j).Text,尽量先在循环外存到临时变量

由于没有系统学过js,只能边学边弄,如有不妥的地方多多执照

0 Answers