mini-react - 实现fiber架构

Fiber架构是一种软件架构,主要用于构建和运行Web应用程序 。它由Facebook开发,是一种基于JavaScript的框架。Fiber架构的核心思想是通过将应用程序逻辑划分为多个小单元(称为"Fiber"),然后在不同的线程或事件循环中执行这些单元,从而提高应用程序的性能和响应速度

在Fiber架构中,每个Fiber代表一个工作单元,可能是一个组件、一个函数或者是一个异步任务。Fiber通过一个调度器来管理这些工作单元的执行。调度器会根据优先级和依赖关系来安排Fiber的执行顺序。当一个Fiber执行完成后,它会被放入一个队列中,等待下一次执行。

Fiber架构的优势在于它可以充分利用现代硬件的多核特性,通过在不同的线程或事件循环中执行不同的Fiber,从而提高应用程序的并发性和性能。同时,Fiber架构还提供了更好的错误处理和调试支持,因为它可以轻松地跟踪和调试每个Fiber的执行过程。

任务调度器把大任务拆分到多个task里面完成,来解决dom树太多一次性加载导致的性能问题。

问题:

如何做到每次只渲染少数几个节点?

在下次执行的时候依然从之前的位置执行?

如何控制树的渲染

以上两个问题可以总结为,我们应该如何控制这颗树的渲染?ok, 我们的想法是:

现在分Task来进行,当一个Task渲染完了,如果还有空闲时间,则会继续下一个;这种一次进行处理的结构可以采用链表结构 。所以现在首先需要做的是,如何将这颗树转化为一个链表结构? 要将这颗树转化为一个链表结构,首先需要知道遍历规则,先遍历谁,接下来又是谁,所以首先需要构建遍历规则。

我们采用"一边构建链表关系,一边渲染dom"

如何控制树的渲染

构建遍历规则

遍历规则从根节点开始,从左到右,每次只构建当前节点和它的孩子节点之间关系

遍历顺序如下:

从root节点开始,找它的子节点,然后是兄弟节点;如果没有兄弟节点就找叔叔节点,知道既没有兄弟节点,也没有叔叔节点就表示遍历完成,形成了一个链表;

结合任务调度器实现执行逻辑

javascript 复制代码
/**
  * 1. 创建dom
  * 2. 处理props
  * 3. 转换链表,设置指针
  * 4. 返回下一个要执行的指针
 */

// 记录下一次任务
let nextWorkOFUnit = false
function workLoop(dleDeadline){
  // 状态 - 表示是否有空闲时间
  let shouldYield = false
  // nextWorkOFUnit 有任务的时候才去执行
  while(!shouldYield && nextWorkOFUnit){
    nextWorkOFUnit = preformWorkOfUnit(nextWorkOFUnit)
    shouldYield = dleDeadline.timeRemaining() < 1
  }
  requestIdleCallback(workLoop)
}
requestIdleCallback(workLoop)

//实现preformWorkOfUnit

function preformWorkOfUnit(work){
  // 1. 创建dom
  // 如果 work 上本身就有了dom,那么就无需去创建处理
  if(!work.dom){
    const dom = (work.dom = work.type === "TEXT_ELEMENT" ? document.createTextNode("") : document.createElement(work.type))

    // 需要将当前的dom 挂载到父节点上
    work.parent.dom.append(dom)

    // 2.处理props
    Object.keys(work.props).forEach(key => {
      if (key !== "children") {
        dom[key] = el.props[key]
      }
    })
  }

  // 3. 转换链表,设置指针
  const childrens = work.props.children
  let prevChild = null
  childrens.forEach((child,index)=>{
    // 因为有挂载 child 和 sibling 那么虚拟dom必然没有这两个属性,不能去破坏虚拟dom的结构
    const newWork = {
      type: child.type,
      props: child.props,
      child: null,
      parent: work,
      sibling: null,
      dom: null
    }
    // 先取第一个子节点 挂载到当前执行任务的子节点上
    if(index === 0){
      work.child = newWork
    }else{
      // 否则就是兄弟节点
      prevChild.sibling = newWork
    }
    prevChild = newWork
  })

  // 4. 返回下一个要执行的指针
  if(work.child){
    return  work.child
  }
  // 然后检查是否有兄弟节点
  if(work.sibling) {
    return work.sibling
  }
  // 如果没有,那么就找到parent ,然后去找叔叔节点
  return work.parent?.sibling
}

github.com/HolinWang/m...

相关推荐
qq_3901617728 分钟前
防抖函数--应用场景及示例
前端·javascript
John.liu_Test1 小时前
js下载excel示例demo
前端·javascript·excel
Yaml41 小时前
智能化健身房管理:Spring Boot与Vue的创新解决方案
前端·spring boot·后端·mysql·vue·健身房管理
PleaSure乐事1 小时前
【React.js】AntDesignPro左侧菜单栏栏目名称不显示的解决方案
前端·javascript·react.js·前端框架·webstorm·antdesignpro
哟哟耶耶1 小时前
js-将JavaScript对象或值转换为JSON字符串 JSON.stringify(this.SelectDataListCourse)
前端·javascript·json
getaxiosluo1 小时前
react jsx基本语法,脚手架,父子传参,refs等详解
前端·vue.js·react.js·前端框架·hook·jsx
理想不理想v1 小时前
vue种ref跟reactive的区别?
前端·javascript·vue.js·webpack·前端框架·node.js·ecmascript
知孤云出岫1 小时前
web 渗透学习指南——初学者防入狱篇
前端·网络安全·渗透·web
贩卖纯净水.1 小时前
Chrome调试工具(查看CSS属性)
前端·chrome
栈老师不回家2 小时前
Vue 计算属性和监听器
前端·javascript·vue.js