一些前置的知识点
1. window.requestAnimationFrame()
该方法需要传入一个回调函数,回调函数会在浏览器下次重绘前执行
,回调函数的执行次数与浏览器刷新次数相匹配(一般1000/60=17ms调用一次)
window.requestAnimationFrame(()=>{
})
2. window.requestIdleCallback()
将在浏览器空闲时间调用js函数队列,使浏览器在空闲时间能够执行低优先级的逻辑而不影响浏览器的动画、输入等响应。
告诉浏览器,我现在执行callback函数,但是它的优先级比较低。告诉 浏览器,可以空闲的时候执行callback,但是如何这个到了超时时间了,就必须马上执行
const works = [work1(){}, work2(){}, work3(){}....]
window.requestIdleCallback(workList,{timeout:50});
//timeout表示如果超过50ms的,浏览器即使没有空闲时间的话也必须执行workList
function workList(deadline){
//deadline是一个对象 有两个属性
// timeRemaining()可以返回此帧还剩下多少时间供队列使用
// didTimeout 此callback任务是否超时
// 如果浏览器有空闲时间或者已经超出了任务的等待时间就立即执行任务队列
if((deadline.timeRemaining() > 1 || deadline.didTimeout)&&works>0){
performUnitOfWork();
}
// 如果没有空闲时间就把控制权交给浏览器,开启下一次调度
if (works.length > 0) {//说明还有未完成的任务
window.requestIdleCallback(workList, { timeout: 1000 });
}
}
function performUnitOfWork() {
works.shift()();
}
但是实际上是用的是MessageChannel实现的空闲时间利用,不是用的requestIdleCallback
3. 链表
链表与树的区别就是,链表能够拿到 节点本身,还能拿到父节点,兄弟节点,子节点
树好比一个棋盘,打乱后很难在摆好原来的位置,链表好比一根绳子,能够迅速找到每个节点的打断的位置。
创建一个链表
// 构造函数 表示链表的一个节点
class Update {//payload数据或者 说元素
constructor(payload, nextUpdate) {
this.payload = payload;
this.nextUpdate = nextUpdate;//指向下一个节点的指针
}
}
// 挂载每个琏表节点。让小火车跑起来
class UpdateQueue {
constructor() {
this.baseState = null;//原状态
this.firstUpdate = null;//第一个更新
this.lastUpdate = null;//最后一个更新
}
enqueueUpdate(update) {
if (this.firstUpdate == null) {
this.firstUpdate = this.lastUpdate = update;
} else {
this.lastUpdate.nextUpdate = update;//上一个最后一个节点的nextUpdate指向自己
this.lastUpdate = update;//让最后一个节指向自己
}
}
//获取老状态。然后遍历这个链表,进行更新 得到新状态
forceUpdate() {
let currentState = this.baseState || {};//初始状态
let currentUpdate = this.firstUpdate;
while (currentUpdate) {
let nextState = typeof currentUpdate.payload == 'function' ?
currentUpdate.payload(currentState) : currentUpdate.payload;
currentState = { ...currentState, ...nextState };//使用当前更新得到新的状态
currentUpdate = currentUpdate.nextUpdate;// 找下一个节点
}
this.firstUpdate = this.lastUpdate = null;//更新完成后要把链表清空
this.baseState = currentState;
return currentState;
}
}
let queue = new UpdateQueue();
queue.enqueueUpdate(new Update({ name: 'aa' }));
queue.enqueueUpdate(new Update({ number: 0 }));
queue.enqueueUpdate(new Update((state) => ({ number: state.number + 1 })));
queue.enqueueUpdate(new Update((state) => ({ number: state.number + 1 })));
console.log(queue);
queue.forceUpdate();
console.log(queue.baseState);
4.fiber架构
fiber是什么
- fiber可以通过某些调度策略合理分配cpu资源,提高响应速度
- 通过fiber架构,让自己的协调阶段可以被中断,适时的让出cpu资源,让浏览器响应用户操作
- 一个数据结构 每一个fiber对应一个dom节点
两个阶段
- render调和阶段
可打断,React 在 workingProgressTree 上复用 current 上的 Fiber 数据结构来一步地(通过requestIdleCallback)来构建新的 tree,标记处需要更新的节点,放入队列中。 - commit提交阶段
不可以被打断,React 将其所有的变更一次性更新到DOM上
网友评论