由一篇文章引发的一系列前端知识学习

背景

偶然看到一篇文章,《前端大容量缓存方案-IndexedDB》-zhuanlan.zhihu.com/p/104536473 在了解IndexedDB过程中,发现了另外一篇文章zhuanlan.zhihu.com/p/95076534 在大佬的主页发现一篇阿里的面试坎坷之路,然后看到了相关的面试知识点www.zhihu.com/column/c_10... 其中讲到了很多知识点,觉得似曾相识,又说不出所以然,于是决定重新学习一遍

首先注意到了"时间切片",因为我们项目里目前也有因响应时间长,页面白屏,影响体验的问题

在了解时间切片的过程中,发现一篇文章zhuanlan.zhihu.com/p/111263128 文章底部,"高性能渲染十万条数据(时间分片)"---juejin.cn/post/684490... 发现了大佬。那么,就倒着学习吧。

菜鸟进阶

1.关于Event Loop、宏任务、微任务

CPU

进程

进程类似工厂的车间,进程之间相互独立,任一时刻,CPU总是运行一个进程,其他进程处于非运行状态。

线程

线程好比车间里的工人,一个进程可以包括多个线程,多个线程共享进程资源。

浏览器是多进程的,一个tab页对应一个进程。

浏览器包含的进程

  • 主进程
  • 第三方插件进程(每种类型的插件对应一个进程,使用时才会创建)
  • GPU进程(用于3D绘制)
  • 渲染进程,及浏览器内核(负责页面渲染,脚本执行,事件处理)

渲染进程包含的线程

  • GUI渲染线程

    • 负责渲染页面,布局和绘制
    • 页面需要重绘和回流时,该线程就会执行
    • 与js引擎线程互斥,防止渲染结果不可预期
  • JS引擎线程

    • 负责处理解析和执行javascript脚本程序
    • 只有一个JS引擎线程(单线程)
    • 与GUI渲染线程互斥,防止渲染结果不可预期(一个渲染,一个改,要是同时进行,岂不是矛盾了)
  • 事件触发线程

    • 用来控制事件循环(鼠标点击、setTimeout、ajax等)
    • 当事件满足触发条件时,将事件放入到JS引擎所在的执行队列中
  • 定时触发器线程

    • setInterval与setTimeout所在的线程
    • 定时任务并不是由JS引擎计时的,是由定时触发线程来计时的
    • 计时完毕后,通知事件触发线程
  • 异步http请求线程

    • 浏览器有一个单独的线程用于处理AJAX请求
    • 当请求完成时,若有回调函数,通知事件触发线程

Event Loop

不管是setTimeout/setIntervalXHR/fetch代码,在这些代码执行时, 本身是同步任务,而其中的回调函数才是异步任务。

宏任务 浏览器为了能够使宏任务DOM任务有序的进行,会在一个宏任务执行结果后,在下一个宏任务执行前,GUI渲染线程开始工作,对页面进行渲染。

主代码块,setTimeout,setInterval等,都属于宏任

微任务

宏任务结束后,会执行渲染,然后执行下一个宏任务,而微任务可以理解成在当前宏任务执行后立即执行的任务

当宏任务执行完,会在渲染前,将执行期间所产生的所有微任务都执行完。

Promise, process.nextTick,属于微任务。

ini 复制代码
`document.body.style = 'background:blue'

console.log(1);

Promise.resolve().then(()=>{ 

  console.log(2);

  document.body.style = 'background:black'

});

console.log(3);`

控制台输出1,3,2,页面的背景色直接变成黑色,没有经过蓝色的阶段,因为执行完微任务才会渲染:

宏任务->微任务->渲染

javascript 复制代码
setTimeout(() => {

    console.log(1)

    Promise.resolve(3).then(data => console.log(data))

}, 0)

setTimeout(() => { console.log(2) }, 0) // print : 1 3 2`

除主代码块外,共有两个宏任务,其中第一个宏任务执行中,输出1,并且创建了微任务队列,所以在下一个宏任务队列执行前,先执行微任务,微任务执行中,输出3,微任务执行后,执行下一次宏任务,执行总输出2。

总结:

先执行一个宏任务,执行过程中,有微任务,则先添加到微任务队列,继续执行当前宏任务,执行完宏任务后,执行所有微任务队列,然后渲染,最后开启下一次宏任务。

链接地址: juejin.cn/post/684490...

2.高性能渲染十万条数据(时间分片)

运行结果如下图:

看完第一部分的Event Loop就不难理解这块了,第一个console打印的是第一次宏任务执行的时间,第二个console打印的是第二个宏任务执行的结束时间,中间的时间差就是渲染的时间

因此我们知道对于大量数据渲染的时候,JS运算不是性能瓶颈,性能瓶颈在于渲染阶段。

优化

方案1: 使用setTimeout分批渲染,明显渲染速度有提升,但是滚动时会出现白屏现象。

该方案的缺点

(1)setTimeout的执行时间并不是设置的时间,只有主线程执行完,才会去检查事件队列中的任务是否需要执行,实际执行事件可能会比其设定的时间晚。

(2)刷新频率受屏幕分辨率和屏幕尺寸的影响,不同设备的刷新频率可能会不同,而setTimeout只能设置一个固定的时间间隔,这个时间不一定和屏幕的刷新时间相同。

方案2:使用requestAnimationFrame

与setTimeout相比,requestAnimationFrame最大的优势是由系统决定回调函数的执行时机。如果屏幕刷新频率是60Hz,那么回调函数就每16.7ms执行一次,如果刷新频率是75Hz,那么这个间隔时间就变成了1000/75=13.3ms。

页面加载速度很快,并且滚动的时候,没有出现闪烁丢帧的现象。

经过以上学习,我对时间分片的理解是,对于大量渲染的任务,性能卡在渲染上,那就把大的宏任务分成若干宏任务,缩短了每个宏任务的渲染时间,这个时间间隔如果和屏幕分辨率保持一致,在视觉上就不会出现白屏卡顿的现象。

相关推荐
空中海7 小时前
第七章:vue工程化与构建工具
前端·javascript·vue.js
zhensherlock7 小时前
Protocol Launcher 系列:Trello 看板管理的协议自动化
前端·javascript·typescript·node.js·自动化·github·js
zhuà!7 小时前
element的el-form提交校验没反应问题
前端·elementui
龙猫里的小梅啊7 小时前
CSS(一)CSS基础语法与样式引入
前端·css
小码哥_常7 小时前
从0到1,开启Android音视频开发之旅
前端
渔舟小调7 小时前
P19 | 前端加密通信层 pikachuNetwork.js 完整实现
开发语言·前端·javascript
qq_12084093718 小时前
Three.js 工程向:Draw Call 预算治理与渲染批处理实践
前端·javascript
不会聊天真君64711 小时前
JavaScript基础语法(Web前端开发笔记第三期)
前端·javascript·笔记
IT_陈寒11 小时前
SpringBoot自动配置这破玩意儿又坑我一次
前端·人工智能·后端