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

背景

偶然看到一篇文章,《前端大容量缓存方案-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。

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

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

相关推荐
天天打码2 分钟前
Esbuild-新一代极速前端构建打包工具
前端·javascript·前端框架
pe7er15 分钟前
深入理解 TypeScript 的模板字面量类型 - 从 ms 库的类型定义说起
前端·typescript
遗憾随她而去.20 分钟前
web前端渡一大师课 03 歌词滚动效果
前端
爱分享的程序员23 分钟前
前端面试专栏-工程化:26.性能优化方案(加载优化、渲染优化)
前端·javascript·node.js
Allen Bright32 分钟前
【vue-5】Vue 3 中的 v-model:双向数据绑定的全面指南
前端·javascript·vue.js
0wioiw032 分钟前
Vue基础(前端教程①-路由)
前端
o翔哥o35 分钟前
🚀 acme.sh —— 免费 SSL 通配符证书 + 自动续期
前端·nginx·https
William Dawson1 小时前
「Chrome 开发环境快速屏蔽 CORS 跨域限制详细教程」*
前端·chrome
兵临天下api1 小时前
《5分钟学会生成API签名:Python实现京东/淘宝认证机制》
前端
邪恶美羊羊1 小时前
Vue 3 + Vite 项目中按需引入 Element Plus (JavaScript)
前端