You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
function diff (oldTree, newTree) {
var index = 0
var patches = {}
dfsWalk(oldTree, newTree, index, patches)
return patches
}
function dfsWalk (oldNode, newNode, index, patches) {
var currentPatch = []
// Node is removed.
if (newNode === null) {
// Real DOM node will be removed when perform reordering, so has no needs to do anthings in here
// TextNode content replacing
} else if (_.isString(oldNode) && _.isString(newNode)) {
if (newNode !== oldNode) {
currentPatch.push({ type: patch.TEXT, content: newNode })
}
// Nodes are the same, diff old node's props and children
} else if (
oldNode.tagName === newNode.tagName &&
oldNode.key === newNode.key
) {
// Diff props
var propsPatches = diffProps(oldNode, newNode)
if (propsPatches) {
currentPatch.push({ type: patch.PROPS, props: propsPatches })
}
// Diff children. If the node has a `ignore` property, do not diff children
if (!isIgnoreChildren(newNode)) {
diffChildren(
oldNode.children,
newNode.children,
index,
patches,
currentPatch
)
}
// Nodes are not the same, replace the old node with new node
} else {
currentPatch.push({ type: patch.REPLACE, node: newNode })
}
if (currentPatch.length) {
patches[index] = currentPatch
}
}
主要比较
如果两个节点是文本节点,比较它们的值是否相等
比较元素的标签名和key是否相等,如果相等则证明是同一个元素,就比较元素的属性和子元素是否相等
如果不属于以上两种情况就重新生成一个新的dom元素
4.patch操作
diff操作将节点之间的差异记录下来,在patch进行更新,其实本质就是dom操作。
var REPLACE // 重新渲染dom节点
var REORDER // 更新子元素
var PROPS // 更新props
var TEXT // 文本节点,更新内容
function applyPatches (node, currentPatches) {
_.each(currentPatches, function (currentPatch) {
switch (currentPatch.type) {
case REPLACE:
var newNode = (typeof currentPatch.node === 'string')
? document.createTextNode(currentPatch.node)
: currentPatch.node.render()
node.parentNode.replaceChild(newNode, node)
break
case REORDER:
reorderChildren(node, currentPatch.moves)
break
case PROPS:
setProps(node, currentPatch.props)
break
case TEXT:
if (node.textContent) {
node.textContent = currentPatch.content
} else {
// fuck ie
node.nodeValue = currentPatch.content
}
break
default:
throw new Error('Unknown patch type ' + currentPatch.type)
}
})
}
目录:
1.由jquery过渡到react的思考
react是当下十分流行的一个专注于view层的库,并不是一个完整的mvvc框架。它的出现掩盖了jquery的锋芒,倍受前端大神们的推崇。
早期的jquery核心是操作dom,但是随着现在的应用越来越复杂,频繁的dom操作会让代码变得难以维护,于是就有人提出了可以把状态和视图绑定在一起,当状态改变就更新视图,这样就摆脱了dom操作,早期的backbone就是这么做的。
但是backbone没有解决的问题是性能问题,更新视图的最原始的方式是把之前的dom树移除,插入一个新的dom树,然而操作dom的成本是十分昂贵的,试想一下:如果我只需要改变一下按钮的颜色,就必须生成一颗新的dom树,这不是很浪费性能吗?所以backbone只适合做一些小型的应用。
react的出现解决了这个性能瓶颈,它在更新视图之前,通过比较两颗新旧虚拟dom,找出差异,然后只更新有差异的那一部分dom,实现了既把状态和视图绑定在一起,又保证了性能。
2.虚拟dom
dom元素3个重要的特性是:
js可以用对象来储存这3个属性,从而模拟dom元素
可以这样使用
可见通过render方法就可以生成一个真正的dom元素,并且把它插入document。
3.diff比较
如果想完整的比较两颗虚拟dom树之间的差别,时间复杂度是 O(n^3) ,这无疑太慢了,是不能运用在开发当中的。由于前端很少会跨级别操作dom,所以diff只会比较同一层级的dom,这样时间复杂度就将为O(n)。
深度优先遍历旧的虚拟dom树,每遍历到一个节点,就和对应的新的虚拟dom树上的节点进行比较。
主要比较
4.patch操作
diff操作将节点之间的差异记录下来,在patch进行更新,其实本质就是dom操作。
5.结语
初学react的人可能会有疑惑:人人都说react的虚拟dom快,性能好,但是实际运用的时候发现和原生的操作dom并没有明显的速度上的差异。其实react从来没有说过它比原生的js快,因为最终的本质都是dom操作,只是它的出现改变了前端的编码方式,从繁杂的dom操作过渡到通过状态的改变更新视图。
The text was updated successfully, but these errors were encountered: