在数组中使用 async/await

194 阅读2分钟

场景描述

最近在做一个 HRM 项目,测试提来一个 bug,在同一张 table 中,一会儿显示 13 条行,一会儿显式 18 条数据。

查找问题

只看复现结果,还以为是内存泄露造成,因为页面一卡一卡的。

看了代码才发现,原来另有乾坤。

async handleData (data) {
      ...

      // 动态添加列
      this.table.columns = this.table.columns.concat([
        {
          label: `${type.slice(-2)}前`,
          prop: 'before',
          render: (h, vm) => {
            const { row, displayValue } = vm
            return row.property === '附件' ? (
              <i-upload value={row.before} readonly></i-upload>
            ) : displayValue
          }
        },
        {
          label: `${type.slice(-2)}后`,
          prop: 'after',
          render: (h, vm) => {
            const { row, displayValue } = vm
            return row.property === '附件' ? (
              <i-upload value={row.after} readonly></i-upload>
            ) : displayValue
          }
        }
      ])
      // 数据格式化
      let list = displayList[this.baseForm.operateType]
      list.forEach(async (k, i) => {
        if (k in propertyMap) {
          let formatter = propertyMap[k].formatter
          let dateFormatter = propertyMap[k].dateFormatter
          this.table.data[i] = {
            property: propertyMap[k].label,
            before: formatter
              ? await dictFormat(formatter, before[k])
              : dateFormatter
                ? dateFormat(before[k])
                : (before[k] || '-'),
            after: formatter
              ? await dictFormat(formatter, after[k])
              : dateFormatter
                ? dateFormat(after[k])
                : (after[k] || '-')
          }
        }
      })
    }

出现问题的猜想

  • 首先:table 的行和列是动态添加的。
  • 其次:行的数据还是异步操作的结果。
  • 最后:这些操作还直接绑定在 table 的数据上。

这样问题就出来了:

  • 动态修改 table 绑定的行列数据,就会频繁修改页面,造成页面卡顿的问题。
  • table 的列获得了一个有 Promise 对象的数组。Promise 对象的状态未知。

修改思路

  • 不直接改 table 绑定的数据,新建一个临时变量,进行操作。
  • 等待所有异步操作结束后,再进行赋值。
    • 这里 forEach 改为 map,因为需要确认异步操作
async handleData (data) {
      if (!data) return
      ...
      // 动态添加列
      this.tempTable.columns = this.tempTable.columns.concat([
        {
          label: `${type.slice(-2)}前`,
          prop: 'before',
          render: (h, vm) => {
            const { row, displayValue } = vm
            return row.property === '附件' ? (
              <i-upload value={row.before} readonly></i-upload>
            ) : displayValue
          }
        },
        {
          label: `${type.slice(-2)}后`,
          prop: 'after',
          render: (h, vm) => {
            const { row, displayValue } = vm
            return row.property === '附件' ? (
              <i-upload value={row.after} readonly></i-upload>
            ) : displayValue
          }
        }
      ])
      // 数据格式化
      let list = displayList[this.baseForm.operateType]
      let temp = list.map(async (k, i) => {
        if (k in propertyMap) {
          let formatter = propertyMap[k].formatter
          let dateFormatter = propertyMap[k].dateFormatter

          return {
            property: propertyMap[k].label,
            before: (formatter
              ? await dictFormat(formatter, before[k])
              : dateFormatter
                ? dateFormat(before[k])
                : (before[k] || '-')),
            after: formatter
              ? await dictFormat(formatter, after[k])
              : dateFormatter
                ? dateFormat(after[k])
                : (after[k] || '-')
          }
        }
      })
      this.tempTable.data = await Promise.all(temp)
      this.table = this.tempTable
    }

思考

  • 查找问题时,在确定 Promise 都执行的情况下,为什么有时候显示 18 条,有时候显示 13 条呢?

相关文档

# 如何在 Array.forEach 中正确使用 Async