微任务链式派生阻塞渲染

测试前两天提给我一个bug,点击一个按钮后页面会卡顿很久,然后才能出现弹窗。

我自己试了一下,点击按钮后,果然整个页面陷入了完全的卡顿,过了一会后弹窗出现,但此时操作页面同样会卡顿,一看就是js执行阻塞了渲染。

我又点击了其他数据同样位置的按钮,此时却一点都不卡顿。

可以推测应该是数据量太大导致处理函数的执行时间过长阻塞了渲染。

数据处理优化

于是找到处理函数,发现其中对列表数据进行了循环,又在循环中在一个大的字典表做字典匹配

ini 复制代码
// 示例代码
async function buildOptions(list) {
    for (let i = 0; i < list.length; i++) {
        const dictList = await getDict(config.dicType);
    }
}
​
async getDict(dicType) {
  let list: DicItem[] = [];
  if (!this.dictionaryList.length) {
    list = await this.getDictAll();
  } else {
    list = this.dictionaryList;
  }
  return list.filter(o => o.id == dicType);
}

由于是大数据的循环套循环,所以只要将字典表做一次循环变为map,就可以让效率提升。

kotlin 复制代码
async getDict(dicType) {
  if (!this.dictionaryList.length) {
    await this.getDictAll();
  }
  return this.dictionaryMap.get(dicType);
}

改好,再次点击按钮,熟悉卡顿、熟悉的掉帧,完全没有效果。

我老老实实的打开performance,查看一下这地方的点击前后的性能分析,发现点击按钮后执行的时间来到了3秒,其中大部分时间都在执行微任务。

我再看处理函数的代码,突然明白了。

同一事件循环中大量微任务阻塞

因为循环中使用了await,当dictionaryList中有值的时候,await创建的Promise会在本轮宏任务中立刻resolve,这时候后续的代码会作为微任务进入到微任务队列中。等执行该微任务的时候,下一次的循环依然会产生新的微任务,也就是 执行微任务=>微任务生成微任务=>执行微任务 这样一个过程直到循环结束。而所有微任务都在同一个宏任务内连续执行,于是浏览器渲染被阻塞。

知道了原因,改正就简单了,只要先执行一次带有await的方法,然后通过同步函数获取就可以了

javascript 复制代码
async function buildOptions(list) {
    await getDict('')
    for (let i = 0; i < list.length; i++) {
        const dictList = getDictSync(config.dicType);
    }
}
// 同步获取字典
function getDictSync(dicType) {
    return this.dictionaryMap.get(dicType) || [];
}

再次查看这个地方的性能分析,总耗时已经降下来了,来到了100ms

关键点: 循环内对同步函数用 await,每个 await 都把下一次循环推迟到微任务队列,前一个微任务执行完又产生下一个微任务,所有微任务连续执行不中断,直到循环结束,浏览器才有机会渲染。

相关推荐
今日无bug2 小时前
大模型的回答是怎么一个字一个字蹦出来的?前端流式输出解析
前端·llm·agent
计算机魔术师2 小时前
Anthropic 复盘 Claude 模型越权访问真实系统事件并改进对齐与安全措施
前端
掘金者阿豪2 小时前
Seedance 2.0/2.5 虚拟素材能跨 Key 共用吗?一次讲清 Asset ID、账号隔离与 SaaS 素材架构
前端·后端
用户50093768390393 小时前
热敏小票 Web 打印:我在 58/80mm 上折腾的两周
前端·vue.js
XGM3 小时前
一个前端新手的"顿悟"时刻:DOM树、渲染原理和JS动态渲染
前端
东方小月3 小时前
一篇文章带你深入拆解Skill的本质与工程实现,让你不再滥用Skill
前端·人工智能·后端
xy34533 小时前
Axure9.0 中继器遮罩的核心应用场景(精准适配列表交互)
前端·ui·html·原型·产品设计·axure9.0
天道kabuto4 小时前
记一次 UnoCSS 样式离奇失效的踩坑复盘
前端
前端小张同学4 小时前
AI全栈开发最佳实践💐
前端·后端·架构
前端 贾公子4 小时前
第09章:上下文与记忆 (6)
开发语言·前端·python