[技术分享]定时器解决后端返回多数据导致页面白屏卡顿的问题

shangjin发布于1 个月前 • 65 次阅读

问题由来

我们在开发过程中会遇到一种情况,当后端返回大量数据时,页面会产生白屏,这是因为浏览器渲染不及时,造成了页面的卡顿,客户在使用过程中,因为页面长时间没有变化,会失去耐心,进而导致大规模的客户流失。于是,我们就想到要是有种办法能及时更新页面就好了。

宏任务和微任务

要解决上面这个问题,我们先来了解宏任务和微任务。这里简单说下,要了解详情,大家可以google下!宏任务是指js主流的任务,不是挂起的任务,比如鼠标点击事件,键盘事件等,微任务就是挂起的任务,比如定时器,Promise.resolve().then()等!这里有两点要注意的地方:

1.同一执行周期中,微任务的优先级更高

2.宏任务和相应的微任务执行完毕,浏览器就会进行一次渲染

宏任务和微任务执行以及浏览器渲染

B = setTimeout(()=>{
  /** 执行完毕需要8ms **/
}, 10)
C = setInterval(()=>{
  /** 执行完毕需要4ms **/
}, 10)
/**js 主线程 执行需要16ms**/
/**鼠标事件A,由用户触发,执行完毕需要8ms**/

接下来我们来看过程:

1.假设用户在6ms的时候点击了按钮,触发了事件A,因为js的执行是单线程的,下面重点来了。

2.前16ms执行主线程,以及挂起的3个任务,A任务,B任务和C任务,因为js的单线程属性,所以每次只能执行一项任务,当我们前16ms结束后,浏览器进行一次渲染,同时执行A任务,注意,不是说任务触发了就会执行。

3.A任务执行后,也就是8ms后,第24ms,执行下一个任务B,因为B先挂起,所以比C先执行

4.第32msB任务执行完毕,执行C任务,4ms后C任务执行完毕,浏览器再次渲染,等待4ms,继续执行新挂起的C任务

看到这里,大家是不是会有个疑问,周期性定时器每隔10ms触发一次,为何前32ms只触发了一次,原因如下:

周期性定时器处于挂起状态时,只会挂起一次,也就是只要待执行任务队列中存在C,那么就不会挂起新的同一定时器,如果C已经在执行了,那么待执行任务队列是可以挂起新的将要执行的定时器C,等待执行!简单来说,就是待执行队列中永远只有1个同一名称的定时器任务。

解决白屏的理论和实践

看了上面的,聪明的你应该想到如何解决问题了吧!没错,就是利用微任务的执行优先权,我们把需要渲染的数据,假设10万条,放入一个周期性定时器C,假设20ms执行一次,一次渲染100条,那么用户没有触发事件的时候,我们渲染后端返回的数据,用户点击事件触发后,事件自动挂起,于是当上一轮定时执行完毕,就会执行用户的事件,从而浏览器进行渲染,完成和用户的一次交互,增加了用户体验!用户事件执行完毕,再度执行定时器!就是这么简单,理论上明白了,实践起来就容易多了!

后记

使用定时器分解任务,总的渲染时间并未减少,只是增加了用户体验,所以说程序的本质就是欺骗客户!laughing~

共收到 0 条回复