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

背景

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

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

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

相关推荐
@菜菜_达33 分钟前
CSS a标签内文本折行展示
前端·css
霸王蟹40 分钟前
带你手写React中的useReducer函数。(底层实现)
前端·javascript·笔记·学习·react.js·typescript·前端框架
托尼沙滩裤1 小时前
【Vue3】实现屏幕共享惊艳亮相
前端·javascript·vue.js
啃火龙果的兔子1 小时前
前端八股文-vue篇
前端·javascript·vue.js
孜然卷k1 小时前
前端处理后端对象类型时间格式通用方法封装,前端JS处理JSON 序列化后的格式 java.time 包中的日期时间类
前端·json
幼儿园技术家1 小时前
微信小程序实现用户进行推客的注册绑定
前端
gwcgwcjava1 小时前
[技术积累]成熟的前端和后端开发框架
前端
bbsh20991 小时前
SiteAzure:SetCookie 未设置Secure
前端·网络·安全·siteazure
Mintopia1 小时前
计算机图形学环境贴图(Environment Mapping)教学指南
前端·javascript·计算机图形学
码农之王1 小时前
(二)TypeScript前置编译配置
前端·后端·typescript