微任务链式派生阻塞渲染

测试前两天提给我一个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 都把下一次循环推迟到微任务队列,前一个微任务执行完又产生下一个微任务,所有微任务连续执行不中断,直到循环结束,浏览器才有机会渲染。

相关推荐
悟空瞎说2 分钟前
我用 PixiJS 撸了个圆桌会议选座系统,从 0 到 1 踩坑全复盘
前端
码云之上17 分钟前
从 SPA 到全栈:AI 时代的前端架构升级实践
前端·架构·ai编程
小陈同学呦28 分钟前
关于如何使用CI/CD做自动化部署
前端·后端
前端Ah28 分钟前
记 华为鸿蒙机型小程序使用uni.createInnerAudioContext() 播放音频播放两次的问题
前端
用户221765927921 小时前
css border-left 怎么设置 border 展示为椭圆
前端
御形封灵1 小时前
纯CSS实现方块下落等待动画
前端·css
Luna-player1 小时前
gitee上的vue项目,刚刚创建了一个分支,怎么在本地上拉取分支项目
前端·vue.js·gitee
徐小夕1 小时前
借助AI,1周,0后端成本,我开源了一款Office预览SDK
前端·vue.js·github
转角羊儿1 小时前
CSS补充重要知识
前端·css
恋猫de小郭1 小时前
Kotlin 在 2.0 - 2.3 都更新了什么特性,一口气带你看完这两年 Kotlin 更新
android·前端·flutter