如果你只写过一个简单的落地页,直接在浏览器里用 document.querySelector 改文字、调样式,会感觉一切都很顺手。可一旦界面膨胀到同时存在信息流、消息、点赞、通知、评论等多个独立更新区域时,手动决定“哪个 DOM 节点该变、什么时候变、还有谁依赖它”就会让开发者的脑子变成一个极易出错的状态管理机。这正是 Facebook 工程师当初面对的压力——并不是操作 DOM 本身难,而是当更新变得频繁且彼此交错,心智成本会远远超过代码量。
在它诞生之前,人们用各种技巧来减少重排和重绘:批量合并修改、小心使用文档片段。但这些本质上仍是手动处理“更新调度”的难题。这个新库给出的方案却异常简单:把界面看作纯函数,UI = f(state)。你只需描述状态对应的视图,由它来找出最高效更新浏览器的方式。从此,开发者从“何时更新哪个节点”的细节里抽身,只关心界面应该长什么样。这个转换,成了前端工程的分水岭。
要理解这一切,先得看清真实 DOM 的工作方式。浏览器读取 HTML 后,会把标签解析成一棵节点树——文档对象模型,每个标签、属性、文本都是树上的一个节点,浏览器依据这棵树决定位置、尺寸和颜色。当某一处内容改变,浏览器通常要重算布局、重绘元素、更新屏幕。对于单个标题的文字替换,这些步骤几乎无感;但若同一帧内发生几十处分散的变更,累积的运算量会迅速挤占帧时间,造成肉眼可见的卡顿。真实 DOM 本身并不慢,问题出在频繁触发更新的使用方式上。
它提出的中间层被称为虚拟 DOM——一个完全驻留在内存里的 JavaScript 对象,是对 UI 的轻量描述。比如一段简单的 HTML 结构,在它内部会被映射成包含 type 和 children 的普通对象,不产生任何真实的 HTML 节点,也不存在于浏览器的 DOM 树中。你可以把它看作一份蓝图:每次状态变化,就生成一份新的虚拟树,与上一次的快照对比,找出最小变动,最后才把这些变动应用到真实 DOM。这种机制把需要手动控制的调度工作自动化了。
最能说明问题的是 React.createElement 这个 API。调用它时,你得到的并不是一个 h1 标签,而是一个纯对象:{ type:'h1', props:{ children:'Hello React' } }。这种表示方法把所有 UI 信息都扁平化为可比较的数据,元素只是对界面的描述而非实例,可以轻易创建、丢弃和对比,不必承受真实节点附带的各种浏览器状态和内存开销。正是这种从“命令浏览器做什么”到“描述界面是什么”的思维转变,让它成为复杂应用的首选基石。
热门跟贴