简要说明:
代码主要用途是通过文件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)
// }
}
优化后代码:
// 同步主表数据到其他表
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)
}
}
优化要点
1、嵌套循环能少用就少用,能不用就不用,优化前用的三层嵌套循环,优化后只用了2层循环,上面代码中我先把所有列头名称及列号提前存储到indexObj对象内,在循环内直接调用indexObj对象,这样可以减少一层for循环,大大提高程序效率
2、重复使用的变量,第一次先存到临时变量,循环里直接使用临时变量
3、循环内尽量少访问工作表,如 sheet.Rows(i).Columns(j).Text,尽量先在循环外存到临时变量
由于没有系统学过js,只能边学边弄,如有不妥的地方多多执照