blockdom:世界上最快的虚拟 dom 库!

家好,很高兴又见面了,我是"高级前端 进阶 ",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发!

今天给大家带来的主题是 blockdom,即号称是世界上最快的虚拟 dom 库。话不多说,直接进入正题!

1.什么是 blockdom

blockdom 号称是世界上最快的虚拟 dom 库。

blockdom 是一个非常快速的虚拟 dom 库,主要卖点是它不是逐个元素地展示 DOM,而是逐块地展示 DOM,其中 block 是一个元素及其所有静态内容和一些特殊标签来表示的动态内容。 这允许 blockdom 在块上使用 cloneNode(true) 并加速 diff 过程,因为这种情况下 vdom 树要小得多。

blockdom 支持块、片段(Fragment)、管理合成事件处理程序(Synthetic Event Handlers)等功能。 但是值得注意的是,blockdom 不是一个框架,它甚至没有组件的概念。 blockdom 旨在成为较底层的抽象层,可以在其上抽象出其他框架。而关于如何创建自定义的框架,blockdom 提供了非常细致的入门文档,这一点可以在文末的参考资料中获取。

同时,blockdom api 体积非常小,只有 6 个创建 vnode 的函数,3 个操作 vdom 树的函数和一个配置对象。目前 blockdom 通过 MIT 协议在 Github上开源,是一个值得了解的前端开源项目。

2.深入理解 blockdom

2.1 黄金法则

根据设计,blockdom 假设虚拟树被相同形状的虚拟树修补(patched)。 当将模板编译成渲染函数(预期用例)时,这很自然。 但这意味着不能用另一种类型的块(或具有不同类型节点的虚拟树)修补块。 为此,需要明确使用 toggler 元素。

const block1 = createBlock(`block1`);
const block2 = createBlock(`block2`);
// 错误:树的形状不一样!!!
{
  const tree = block1();
  mount(tree, document.body);
  patch(tree, block2());
}
// 正确:树使用toggler元素来区分两个子树
{
  const tree = toggler("tree1", block1());
  mount(tree, document.body);
  patch(tree, toggler("tree2", block2()));

2.2 操纵虚拟节点 vnodes

blockdom 提供三个功能:

下面是不同的 vnode 类型:

可以通过下面的方式创建 block:

const block = createBlock(`hello blockdom`);

当处理固定数量的 vnode 时,multi block 很有用。 例如,具有多个连续元素的模板。 此外,它的部分或全部 vnode 可以是 undefined,特别适合 children 元素的条件渲染。 如果子节点是 undefined,那么将自动使用空的 text 节点替换:

const block1 = createBlock(`1`);
const block2 = createBlock(`2`);

const tree = multi([block1(), block2()]);
// represents `12`
const otherTree = multi([block1(), undefined]);
// represents `1`

comment 节点的使用则非常简单:

// represents 3 text nodes: blackyellowred
const tree = comment("some text");
// will be rendered as: ""

更多节点类型的使用可以查看文末的参考资料,这里不再继续展开。

扩展 blockdom

blockdom 旨在用作实际框架中的底层实现, 一些框架(例如 Owl,blockdom 正在研究的框架)将需要一种方法来添加某种组件系统。 为此,最好的方法似乎是添加新类型的 vnode。

下面是 blockdom vnode 的接口:

export interface VNode {
  mount(parent: HTMLElement, afterNode: Node | null): void;
  moveBefore(other: T | null, afterNode: Node | null): void;
  patch(other: T, withBeforeRemove: boolean): void;
  beforeRemove(): void;
  remove(): void;
  firstNode(): Node | undefined;
}

所以,要添加一个新的 vnode 类型,只需要用这些方法定义一个对象或一个类,它将与 mount/patch/remove 方法一起工作。

注意 beforeRemove 方法:它是一种用于让框架知道 vnode 将被删除的方法,该方法在删除节点之前被调用。

3.blockdom 性能

3.1 blockdom 与其他框架性能对比

凭借其基于 block 的设计,blockdom 可以在内部使用 cloneNode(true) 方法在一次调用中快速创建 dom 元素,而不是多次调用。 此外,blockdom 的虚拟树要小得多,这反过来又大大加快了 diff 过程。

javascript web 框架基准测试在一套标准化的基准测试中比较了许多框架。 下面是 blockdom 与 vanilla js 、solid(快速细粒度反应框架)和 ivi(最快的虚拟 dom 实现)相比的性能数据。

请注意,这种比较并不完全公平,因为 blockdom 并不是一个真正的框架。 基于 blockdom 构建的框架将有一定的额外开销,具体取决于功能集。 因此,在此基准测试中,基于虚拟 dom 的框架可能会比 solidjs 稍慢。

3.2 为什么 blockdom 这么快

blockdom 之所以快是因为一个基本的设计选择,即用 block 树(tree of blocks)而不是元素来表示虚拟 dom。 这意味着:

还有另一种设计选择使其速度更快,即假设虚拟树总是用相同结构的虚拟树 patch(切换器元素除外),因此下面也是一个很重要的原因。

4.使用 blockdom

4.1 安装 blockdom

可以通过如下 npm 方式进行安装:

npm i blockdom
yarn add blockdom

当然也可以通过静态 CDN 的方式直接引入:

https://unpkg.com/blockdom@{VERSION}/dist/blockdom.iife.min.js

// for the latest version
https://unpkg.com/blockdom/dist/blockdom.iife.min.js

4.2 blockdom 示例

blockdom 允许开发者可以使用更大的 dom 单元在 blockdom 中工作,而不是像 h('p', {}, [...some children]) 那样,比如下面的例子:

// 创建一个block类型
const block = createBlock(
  `

hello

` ); const subBlock = createBlock(`some value: `); // 创建一个 blockdom 虚拟树 const tree = block([], [subBlock(["blockdom"])]); // 挂载虚拟树 mount(tree, document.body); // 输出结果: //

hello

some value: blockdom

上面的示例显示了 mount 功能。下面是一个更有趣的例子,其是一个动态的计数器列表,具有处理程序、列表和动态内容:

const counterBlock = createBlock(`
    
        
        Value: 
    `);

const mainBlock = createBlock(`
    
        
        
    `);

const state = [{ id: 0, value: 3 }];

function addCounter() {
  state.push({ value: 0, id: state.length });
  update();
}

function incrementCounter(id) {
  const counter = state.find((c) => c.id === id);
  counter.value++;
  update();
}

function render(state) {
  const counters = state.map((c) => {
    const handler = [incrementCounter, c.id];
    return withKey(counterBlock([c.value, handler]), c.id);
  });
  return mainBlock([addCounter], [list(counters)]);
}

let tree = render(state);
mount(tree, document.body);

function update() {
  patch(tree, render(state));
}

需要注意的是,block 类型需要首先创建,其具有特殊属性或标记,例如 或 block-handler-1="click"。

blockdom 然后处理 block 模板,找到所有特殊标签、属性并生成将创建和更新这些值的快速函数(fast functions),该数字对应于构建 block 时给出的数据的索引。

此外,blockdom 支持合成处理程序(意思是它只在 body 上设置一个实际的事件处理程序,这是一种优化)。 要使用此功能,只需使用 .synthetic 后缀即可:

const counterBlock = createBlock(
  ``
);

也可以在捕获模式下设置处理程序:

const counterBlock = createBlock(
  ``
);

5.本文总结

本文主要和大家介绍下 blockdom,即号称是世界上最快的虚拟 dom 库。相信通过本文的阅读,大家对 blockdom 会有一个初步的了解。

因为篇幅有限,文章并没有过多展开,如果有兴趣,可以在我的主页继续阅读,同时文末的参考资料提供了大量优秀文档以供学习。最后,欢迎大家点赞、评论、转发、收藏!


参考资料

https://github.com/ged-odoo/blockdom

https://github.com/ged-odoo/blockdom/blob/main/doc/reference.md#the-golden-rule

https://github.com/ged-odoo/blockdom/blob/main/doc/extending_blockdom.md

https://github.com/ged-odoo/blockdom/blob/main/doc/performance_notes.md

https://github.com/ged-odoo/blockdom/blob/main/doc/make_your_own_framework/readme.md

https://devpress.csdn.net/react/62ec6af219c509286f416f8d.html

展开阅读全文

页面更新:2024-03-01

标签:节点   参考资料   函数   框架   元素   最快   过程   类型   快速   程序   方法

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2008-2024 All Rights Reserved. Powered By bs178.com 闽ICP备11008920号-3
闽公网安备35020302034844号

Top