前言
前段时间实现了一个使用opencvjs将印花图与mask图原图进行正片叠底的效果,印花使用四方连续的形式拼接,大概效果如下图所示
测试反馈说生成图时操作会变得卡顿,于是便开始着手优化了。
找到问题
打开performance录下操作,发现有长任务需要优化。
可以发现有一个比较长的任务,我们看看调用栈分析一下哪个函数时间比较长。从图上可以发现整个task主要耗时的函数有getSourceMatAndMaskMat和mergeImage两个。查看一下render函数
拆分long task
对于主线程中的长任务可以使用在 Promise 中调用 setTimeout 的方式让出主线程。
export function yieldToMain() {
return new Promise((resolve) => {
setTimeout(resolve, 0);
});
}
在两个函数之间加上yieldToMain
再录一次操作发现顺利拆分了
那么继续看看getSourceMatAndMaskMat这个函数里面哪些需要拆出来的
拆分for循环中的long task
可以看到getSourceMatAntMaskMat主要耗时是在loopRect这个循环中,看看loopRect做了什么
主要是做了遍历区域像素的操作,就算是100x100的遍历也要遍历10000次,我们可以试一下将长循环拆分成多个批次来进行,接下来我们试一下改造loopRect函数来拆分一下。
看看效果
可以看出,long task被成功拆分了,从原先一整个task超过200ms的任务,变成了一个个任务块,最大的任务块也就40ms左右,也就是在生成图的过程中是不会影响用户其他操作的。
一些补充
尽量不要使用匿名函数
在函数编写中,尽量不要使用匿名函数来创建函数,因为这会使你在查找函数栈时变得复杂
从图上很难直观得看出这是个什么函数,到底做了什么。
函数封装
每一个功能应该拆分出一个函数出来,每个函数要尽量只做一个事情,拆分成函数才能更好地拆分task。如何拆分函数可以看看代码整洁之道的第三章
结语
合理利用chrome performance板块,我们可以将一个个long task给切分成一个个比较小的任务块,减少我们因为长任务导致的操作卡顿。