声明式用户界面
编写声明式UI的传统方法是更改元素的innerHTML属性。例如,如果我想向 我们可以认识到innerHTML允许我们以声明地方式定义UI,但它的效率不高。 效率低下源于每次更改用户界面时的解析、破坏和重建innerHTML,都需要遵循四个步骤: 这个过程在计算上非常昂贵,并且可能导致渲染速度显著降低。 那么,这个问题是如何解决的呢?那就是选择使用DOM, 这种方法要比innerHTML方法快3倍。 然而,我们可以认识到,手动编写这个可能很麻烦,特别是当UI中有很多交互时,因为我们需要命令式地指定每个步骤。以声明的方式编写UI要优雅得多。 不过,React作者创建了VirtualDOM,允许我们以一种比innerHTML更快的呈现方式编写UI,而且是声明式的。 为了最好地了解VirtualDOM是如何工作的,让我们概述一下流程,然后构建一个示例。 VirtualDOM是一种呈现UI的方法。该方法利用模仿DOM树的JavaScript对象树(“虚拟”节点)。 以上 我们可以注意到虚拟节点有三个属性: 使用虚拟节点,我们可以对当前的UI进行建模,以及当我们更新UI时希望它改变成什么。 假设我想将 但是使用VirtualDOM,我可以指定当前UI的外观(旧虚拟节点)和我希望它的外观(新虚拟节点)。 然而要让Virtual DOM真正将更改应用到UI,还需要计算旧虚拟节点和新虚拟节点之间的差异。 当我们知道了二者之间的差别,就可以通过Virtual DOM改变UI。 Virtual DOM只是进行了必要的修改,并不是替换了整个UI。 在本文中,我们将模仿Million.js的 Virtual DOM API。我们的API将包含三个主要功能:m, createElement, and patch。 m 函数是创建虚拟节点的辅助函数。虚拟节点包含三个属性: m帮助程序函数的示例实现如下: 这样创建虚拟节点就简单多了。 该createElement函数将虚拟节点转换为真实的DOM元素。这很重要,因为我们将在patch函数中使用它。 实现如下: 这样就可以轻松地将虚拟节点转变成DOM节点。 该patch函数采用现有的DOM节点、旧的虚拟节点和新的虚拟节点。 实现如下: 这样就可以使用patch功能更新UI了。 当前,Virtual DOM实现在计算新旧虚拟节点之间的差异时会产生计算成本。 即使使用非常有效的差分算法 (如list-diff2),当虚拟节点树大于虚拟节点的两位数时,差异成本也会变得显著。 树区分算法是出了名的慢。时间复杂度可以从O(n)转O(n ^ 3)取决于虚拟节点树的复杂性。这与DOM操纵相去甚远,后者是O(1)。 编译器是新框架”-- 汤姆·戴尔 Ember的创建者汤姆是最早倡导为JavaScript UI库使用编译器开源狂热者之一。 现在,我们知道汤姆的赌注是正确的。JavaScript生态系统见证了Solid、Svelte等“已编译”库的兴起,它们放弃了Virtual DOM。这些库使用编译器预渲染,并在使用时生成代码来跳过不必要的渲染。 另一方面,Virtual DOM落后于这一趋势。当前的虚拟DOM库本质上与“按需” 编译器不兼容。因此,Virtual DOM的渲染速度通常是比现代“No Virtual DOM” UI库慢几个数量级。 如果我们希望Virtual DOM在未来的渲染速度上具有竞争力,那就需要重新设计Virtual DOM以允许编译器增强。 免责声明: ① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。 ② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341 193.9 KB下载数265 191.63 KB下载数245 143.91 KB下载数1148 183.71 KB下载数642 644.84 KB下载数2756document.body.innerHTML = '<div>Hello World!div>';
// <body> now has a <div>Hello World!div> child.命令式用户界面
const div = document.createElement('div');
div.textContent = 'Hello World!';
document.body.appendChild(div);理解VirtualDOM
// <div>Hello World!div>
const div = document.createElement('div');
div.style = 'color: red';
div.textContent = 'Hello World!';const divVNode = {
type: 'div',
props: {
style: 'color: red'
}
children: ['Hello World!']
};// <div>Hello World!div>
const div = document.createElement('div');
div.style = 'color: red';
div.textContent = 'Hello World!';
// Change from "Hello World!" to "Hello Universe!"
div.textContent = 'Hello Universe!';const oldVNode = {
type: 'div',
props: {
style: 'color: red'
}
children: ['Hello World!']
};
const newVNode = {
type: 'div',
props: {
style: 'color: red'
}
children: ['Hello Universe!']
};{
type: 'div',
props: {
style: 'color: red'
}
- children: ['Hello World!']
+ children: ['Hello Universe!']
};div.replaceChild(newChild, oldChild);
构建自己的Virtual DOM
m (tag, props, children)
const m = (tag, props = {}, children = []) => ({
tag,
props,
children,
});m('div', { style: 'color: red' }, ['Hello World!']);
#createElement(vnode)
const createElement = (vnode) => {
if (typeof vnode === 'string') {
return document.createTextNode(vnode);
}
const el = document.createElement(vnode.tag);
for (const prop in vnode.props) {
el[prop] = vnode.props[prop];
}
for (const child of vnode.children) {
el.appendChild(createElement(child));
}
return el;
};// <div style="color: red">Hello World!div>
createElement(
m('div', { style: 'color: red' }, ['Hello World!'])
);#patch(el, newVNode, oldVNode)
const patch = (el, newVNode, oldVNode) => {
if (!newVNode && newVNode !== '') return el.remove();
if (
typeof oldVNode === 'string' ||
typeof newVNode === 'string'
) {
if (oldVNode !== newVNode) {
return el.replaceWith(createElement(newVNode));
}
} else {
if (oldVNode.tag !== newVNode.tag) {
return el.replaceWith(createElement(newVNode));
}
// patch props
for (const prop in {
...oldVNode.props,
...newVNode.props,
}) {
if (newVNode.props[prop] === undefined) {
delete el[prop];
} else if (
oldVNode.props[prop] === undefined ||
oldVNode.props[prop] !== newVNode.props[prop]
) {
el[prop] = newVNode.props[prop];
}
}
// patch children
for (let i = oldVNode.children.length - 1; i >= 0; --i) {
patch(
el.childNodes[i],
newVNode.children[i],
oldVNode.children[i]
);
}
for (
let i = oldVNode.children.length;
i < newVNode.children.length;
i++
) {
el.appendChild(createElement(newVNode.children[i]));
}
}
};const oldVNode = m('div', { style: 'color: red' }, [
'Hello World!',
]);
const newVNode = m('div', { style: 'color: red' }, [
'Hello Universe!',
]);
const el = createElement(oldVNode);
// <div style="color: red">Hello World!div>
patch(el, oldVNode, newVNode);
// <div style="color: red">Hello Universe!div>Virtual DOM是纯开销
Virtual DOM的未来
软考中级精品资料免费领
相关文章
发现更多好内容猜你喜欢
AI推送时光机Python CPython 的历史演变与未来展望
HTML 段落标签的沿革:从历史到未来
HTML 有序列表的演变:回顾历史并展望未来
Go语言的发展历程和未来趋势
谈谈PHP的发展历程和未来趋势
Go语言的发展历程和未来展望
如何使用Python和Numpy来分析Git提交历史?
JavaScript 25年来的历史进程是怎样的
MySQL的架构和历史是怎样的
关于Diablo3的历史和现状思考