手写react--fiber架构如何中断和恢复

这篇具有很好参考价值的文章主要介绍了手写react--fiber架构如何中断和恢复。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

/** @jsxRuntime classic */

//**============== */

const Didact = {
  createElement,
  render,
};

function createTextElement(text) {
  return {
    type: "TEXT_ELEMENT",
    props: {
      nodeValue: text,
      children: [],
    },
  };
}

function createElement(type, props, ...children) {
  return {
    type,
    props: {
      ...props,
      children: children.map((child) =>
        typeof child === "object" ? child : createTextElement(child)
      ),
    },
  };
}

/** @jsx Didact.createElement */
const element = (
  <div id="foo">
    <a>bar</a>
    <b />
  </div>
);
// const element = Didact.createElement(
//   "div",
//   { id: "foo" },
//   Didact.createElement("a", null, "bar"),
//   Didact.createElement("b")
// );

function createDom(fiber) {
  const dom =
    fiber.type == "TEXT_ELEMENT"
      ? document.createTextNode("")
      : document.createElement(fiber.type);

  const isProperty = (key) => key !== "children";
  Object.keys(fiber.props)
    .filter(isProperty)
    .forEach((name) => {
      dom[name] = fiber.props[name];
    });

  return dom;
}

function commitRoot() {
  commitWork(wipRoot.child);
  wipRoot = null;
}

function commitWork(fiber) {
  if (!fiber) {
    return;
  }
  const domParent = fiber.parent.dom;
  domParent.appendChild(fiber.dom);
  commitWork(fiber.child);
  commitWork(fiber.sibling);
}

let nextUnitOfWork = null;
let wipRoot = null;
let currentRoot = null;

function workLoop(deadline) {
  let shouldYield = false;
  while (nextUnitOfWork && !shouldYield) {
    nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
    shouldYield = deadline.timeRemaining() < 1;
  }
  if (!nextUnitOfWork && wipRoot) {
    commitRoot();
  }
  requestIdleCallback(workLoop);
}

requestIdleCallback(workLoop);

//获取工作的第一个节点 执行工作,而且返回下一个工作单元
function performUnitOfWork(fiber) {
  if (!fiber.dom) {
    fiber.dom = createDom(fiber);
  }
  const elements = fiber.props.children;
  let index = 0;
  let prevSibling = null;
  while (index < elements.length) {
    const element = elements[index];
    const newFiber = {
      type: element.type,
      props: element.props,
      parent: fiber,
      dom: null,
    };
    if (index === 0) {
      fiber.child = newFiber;
    } else {
      prevSibling.sibling = newFiber;
    }
    prevSibling = newFiber;
    index++;
  }
  if (fiber.child) {
    return fiber.child;
  }
  let nextFiber = fiber;
  while (nextFiber) {
    if (nextFiber.sibling) {
      return nextFiber.sibling;
    }
    nextFiber = nextFiber.parent;
  }
}

function render(element, container) {
  wipRoot = {
    dom: container,
    props: {
      children: [element],
    },
    alternate: currentRoot,
  };
  nextUnitOfWork = wipRoot;
}

const container = document.getElementById("root");
Didact.render(element, container);

React 17 版本开始提供了一个新的JSX转换方案。在之前,JSX 代码会被默认编译成 React.createElement(...) ,而使用新 JSX 方案后,会从一个独立的模块react/jsx-runtime中引入 JSX 函数。

babel插件@babel/plugin-transform-react-jsx

/** @jsxRuntime classic */  babel运行时转换

render 创建最初始的fiber对象,render执行完之后会执行workLoop方法,开发fiber任务

function render(element, container) {
  wipRoot = {
    dom: container,
    props: {
      children: [element],
    },
    alternate: currentRoot,
  };
  nextUnitOfWork = wipRoot;
}

如果存在下一个fiber任务那么就行执行performUnitOfWork,如果没有说明fiber树构建完毕,执行commitRoot 提交进行页面渲染。

function workLoop(deadline) {
  let shouldYield = false;
  while (nextUnitOfWork && !shouldYield) {
    nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
    shouldYield = deadline.timeRemaining() < 1;
  }
  if (!nextUnitOfWork && wipRoot) {
    commitRoot();
  }
  requestIdleCallback(workLoop);
}

performUnitOfWork构建fiber树且返回下一个fiber任务

//获取工作的第一个节点 执行工作,而且返回下一个工作单元
function performUnitOfWork(fiber) {
  if (!fiber.dom) {
    fiber.dom = createDom(fiber);
  }
  const elements = fiber.props.children;
  let index = 0;
  let prevSibling = null;
  while (index < elements.length) {
    const element = elements[index];
    const newFiber = {
      type: element.type,
      props: element.props,
      parent: fiber,
      dom: null,
    };
    if (index === 0) {
      fiber.child = newFiber;
    } else {
      prevSibling.sibling = newFiber;
    }
    prevSibling = newFiber;
    index++;
  }
  if (fiber.child) {
    return fiber.child;
  }
  let nextFiber = fiber;
  while (nextFiber) {
    if (nextFiber.sibling) {
      return nextFiber.sibling;
    }
    nextFiber = nextFiber.parent;
  }
}

fiber对象和真实的dom对象挂钩。

 if (!fiber.dom) {
    fiber.dom = createDom(fiber);
  }

处理fiber对象的子元素,且为对应的子元素创建fiber对象,这个时候子元素fiber对象的dom属性还是空。如果是第一个子元素,那么把第一个子元素的fiber对象挂到父fiber对象的child属性上。如果不是父fiber的第一个子元素,那么把该fiber对象挂到它前面一个fiber对象的sibling属性上。(也就是只创建了父fiber直接子元素对应的fiber对象,但是还没有处理子元素对应的fiber任务)

let index = 0;
  let prevSibling = null;
  while (index < elements.length) {
    const element = elements[index];
    const newFiber = {
      type: element.type,
      props: element.props,
      parent: fiber,
      dom: null,
    };
    if (index === 0) {
      fiber.child = newFiber;
    } else {
      prevSibling.sibling = newFiber;
    }
    prevSibling = newFiber;
    index++;
  }

手写react--fiber架构如何中断和恢复,React,react.js,javascript,前端

手写react--fiber架构如何中断和恢复,React,react.js,javascript,前端

 返回下一个fiber任务,如果有子元素,那么处理第一个子元素。如果没有子元素,那么处理它兄弟节点,如果没有兄弟节点,那么返回父节点。然后寻找父元素的兄弟节点,一直找到最初始节点。当performUnitOfWork没有可以返回的节点,那么说明fiber树构建完成,执行commitRoot渲染页面。(每一个fiber任务处理完都可以中断,如果恢复,那就是继续处理nextUnitOfWork。所以fiber任务的终断和恢复是在fiber树构建阶段)

 if (fiber.child) {
    return fiber.child;
  }
  let nextFiber = fiber;
  while (nextFiber) {
    if (nextFiber.sibling) {
      return nextFiber.sibling;
    }
    nextFiber = nextFiber.parent;
  }

页面渲染:

commitWork(wipRoot.child); //从最外层开始

wipRoot = null;//开始渲染要把wipRoot置为null,因为下一次页面刷新还会重新构建。

const domParent = fiber.parent.dom;

domParent.appendChild(fiber.dom);

commitWork(fiber.child);

commitWork(fiber.sibling);

通过递归添加子dom节点到父dom上面。最后完成渲染。(这个时候是无法中断的,其实这里也可以实现中断,只是这里没有实现,原理和上面一样,所有处理绑定在一个对象上面,就可以实现中断和恢复文章来源地址https://www.toymoban.com/news/detail-598382.html


function commitRoot() {
  commitWork(wipRoot.child);
  wipRoot = null;
}

function commitWork(fiber) {
  if (!fiber) {
    return;
  }
  const domParent = fiber.parent.dom;
  domParent.appendChild(fiber.dom);
  commitWork(fiber.child);
  commitWork(fiber.sibling);
}

到了这里,关于手写react--fiber架构如何中断和恢复的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 深入理解React中fiber

    Fiber是对React核心算法的重写,Fiber是React内部定义的一种数据结构,将更新渲染耗时长的大任务,分为许多的小片。Fiber节点保存啦组件需要更新的状态和副作用,一个Fiber代表一个工作单元。 在react中,主要做了下面这些操作: 为每个增加了优先级,优先级高的任务可以中断

    2024年02月07日
    浏览(33)
  • React18原理: React核心对象之ReactElement对象和Fiber对象

    React中的核心对象 在React应用中,有很多特定的对象或数据结构.了解这些内部的设计,可以更容易理解react运行原理 列举从react启动到渲染过程出现频率较高,影响范围较大的对象,它们贯穿整个react运行时 如 ReactElement 对象 如 Fiber 对象 其他过程的重要对象 如事件对象(位

    2024年02月19日
    浏览(32)
  • 学习篇之React Fiber概念及原理

    React Fiber 是 React 框架的一种底层架构,为了改进 React 的渲染引擎,使其更加高效、灵活和可扩展。 传统上,React 使用一种称为堆栈调和递归算法来处理虚拟 DOM 的更新,这种方法在大型应用或者频繁更新的情况下可能会产生性能问题。React Fiber 则是基于一种增量渲染的思想

    2024年02月12日
    浏览(38)
  • JavaScript 框架比较:Angular、React、Vue.js

    在 Web 开发领域,JavaScript 提供大量技术栈可供选择。其中最典型的三套组合,分别是 MERN、MEAN 和 MEVN。这些首字母相同的选项各自代表不同的技术加工具组合。为了在这些技术栈中做出明智选择,让我们先从核心组件聊起,再对各自前端框架(React、Angular 和 Vue)进行简化比

    2024年01月20日
    浏览(56)
  • 使用 React Three Fiber 和 GSAP 实现 WebGL 轮播动画

    参考:Building a WebGL Carousel with React Three Fiber and GSAP 在线 demo github 源码 效果来源于由 Eum Ray 创建的网站 alcre.co.kr,具有迷人的视觉效果和交互性,具有可拖动或滚动的轮播,具有有趣的图像展示效果。 本文将使用 WebGL、React Three Fiber 和 GSAP 实现类似的效果。通过本文,可以了

    2024年02月05日
    浏览(57)
  • JavaScript框架 Angular、React、Vue.js 的全栈解决方案比较

    在 Web 开发领域,JavaScript 提供大量技术栈可供选择。其中最典型的三套组合,分别是 MERN、MEAN 和 MEVN。前端框架(React、Angular 和 Vue)进行简化比较。 MERN 技术栈包含四大具体组件: MongoDB:一款强大的 NoSQL 数据库,以灵活的 JSON 格式存储数据。 Express.js:一套极简但强大的

    2024年02月03日
    浏览(54)
  • 2023年最佳JavaScript框架:React、Vue、Angular和Node.js的比较

    🎉欢迎来到Java学习路线专栏~探索2023年最佳JavaScript框架:React、Vue、Angular和Node.js的比较 ☆* o(≧▽≦)o *☆嗨~我是IT·陈寒🍹 ✨博客主页:IT·陈寒的博客 🎈该系列文章专栏:Java学习路线 📜其他专栏:Java学习路线 Java面试技巧 Java实战项目 AIGC人工智能 🍹文章作者技术和水

    2024年02月11日
    浏览(47)
  • Node.js npm V8 React Express的运行配合关系:构建JavaScript应用的基石

    目录 Node.js 和 V8 引擎 Node.js 和 npm LTS(Long Term Support) React Node.js的作用 Express Node.js 和 V8 引擎 Node.js 使用 Google 的 V8 JavaScript 引擎 来执行 JavaScript 代码。V8 是一个高性能的 JavaScript 和 WebAssembly 引擎,用于在 Google Chrome 浏览器和 Node.js 中运行 JavaScript。 V8 引擎的更新 通常包括

    2024年03月12日
    浏览(59)
  • 手写一个 React 图片预览组件

    原文链接: 手写一个 React 图片预览组件 前几天打算给博客添加一个图片预览的效果,可在网上找了半天也没找到合适的库,于是自己干脆自己手写了个。 最终实现效果如下: 当鼠标点击图片时生成一个半透明遮罩,并添加一个与点击图片位置大小都相同的图片,之后通过

    2024年02月08日
    浏览(37)
  • 如何使用前端框架(React、Angular、Vue.js等)?该如何选择?

    聚沙成塔·每天进步一点点 前端入门之旅:探索Web开发的奇妙世界 欢迎来到前端入门之旅!感兴趣的可以订阅本专栏哦!这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发者,这里都将为你提供一个系统而

    2024年02月07日
    浏览(56)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包