【问题标题】:I know its bad to store data in the DOM, but why?我知道将数据存储在 DOM 中是不好的,但为什么呢?
【发布时间】:2011-05-06 01:42:51
【问题描述】:

我一遍又一遍地听说“将 DOM 用作数据库”是不好的做法。

虽然我基本同意这种观点,但这个问题更多的是关于非黑白案例。记住 jQuery 的 .data() 方法和 HTML5 数据属性规范的最新修订,为了方便而将一些数据粘贴到 DOM 中真的有那么糟糕吗?

例如,我最近通过执行以下操作在充满输入的表上实现了“实时”计算功能:

<table>
  <tr>
    <td><input type="text"></td>
  </tr>
  <tr>
    <td><input type="text"></td>
  </tr>
</table>

jQuery:

$('table').bind('calculate',function(){
  var total = 0;
  $(this).find('tr').each(function(){
    total += $(this).data('value');
  });
  // display total
});

$('table input').bind('change keyup',function(){
  $(this).closest('tr').data('value',$(this).val());
  $(this).closest('table').trigger('calculate');
});

这是一个过于简化的示例,因为我可以跳过对.data() 的调用并直接进入输入值,但让我们想象一个稍微复杂一点的场景,其中输入以外的元素正在影响行值。

这种情况下使用DOM存储简单数据有错吗?

【问题讨论】:

  • DOM 树中的节点数据。
  • 触摸。但你知道我的意思......人们建议我总是在这里创建某种记忆模型。这样可以省去我的麻烦还是真的可以吗?
  • 我要么误解了这个问题,要么误解了 jQuery 的 data() 方法的工作原理。我认为 jQuery 将这些值存储在其缓存中,而不是直接将数据附加到 DOM。
  • @kennis,也不行!我只是不知道 jQuery 的 data() 方法将值存储在缓存中。我对此感到困惑:As of jQuery 1.4.3 HTML 5 data- attributes will be automatically pulled in to jQuery's data object. The treatment of attributes with embedded dashes was changed in jQuery 1.6 to conform to the W3C HTML5 specification. 我只是假设由于 data-attributes 和 .data() 似乎是耦合的,所以 jQuery 正在使用 DOM。但显然还有一些其他的魔法正在发生。我应该检查一下来源...
  • jQuery claims 不将其存储在 DOM 中:“数据属性在第一次访问数据属性时被拉取,然后不再访问或改变(所有数据值随后内部存储在 jQuery 中)。”

标签: javascript jquery dom


【解决方案1】:

可以将数据存储在 DOM 对象中。由于您的问题是针对 jQuery 的数据 API 的,因此了解 data API 的工作原理非常重要。不久前我写了一个answer 解释它的内部工作原理。数据 API 仅保留对 DOM 对象的引用以及数据,并且不会在 DOM 对象本身内部存储任何内容。所有数据都存储在普通的旧 JavaScript 对象中。

这是一个好方法还是坏方法的问题是个人品味的问题。 jQuery 的创建者 John Resig 在 2010 年的 Tech4Africa 上发表了演讲,他谈到了这个确切的问题,并建议取消单独的存储区域并使用数据 API 将所有内容与 DOM 链接。你可以在YouTube 上看到演讲(感谢@tine2k 提供链接)。如果您听完整篇演讲,您会发现一些很好的例子,说明为什么这种方法有意义并且让事情变得简单。

我相信可以为光谱的另一端提出类似的论点 - 将您的数据整齐地隐藏在对象和中,并与视图本身分开。这种想法来自于 MVC 等传统架构。

我说两种方法都可以——使用 DOM 存储数据,或者使用经典方法。只是不要将两者混为一谈,因为那样你的应用程序模型到处都是。

【讨论】:

  • 很高兴你解决了这个问题。我有 95% 的把握认为 data() 使用了 jQuery 的缓存,而不是实际将数据存储在 DOM 中。
  • 我在 Youtube 上找到了提到的视频:youtube.com/watch?v=78cuwVtMe2Y
  • @tine2k 你介意我将 youtube 链接添加到答案中吗?当然:)?
  • 只是好奇。如果我们使用 React.js 或 vue.js,我们是否需要数据集 API 来存储数据,因为我们可以通过参数传递数据&lt;button onClick={this.deleteRow.bind(this, id)}&gt;Delete Row&lt;/button&gt;
【解决方案2】:

有一些反对使用 DOM 存储数据的基本论点:

  1. DOM 应该是数据视图。 DOM 元素的属性应该是元素本身的元数据,而不是来自模型的数据。

  2. 您不应该向宿主对象添加随机属性,因为您不知道它们可能对它们做什么。

  3. 您遇到与全局变量相同的问题 - 如果这成为惯例,您将不得不采用一种方案来避免名称冲突。

还有一种观点认为 DOM 是一个非常普通的数据存储,具有索引的对象结构对于除了琐碎的数据需求之外的任何事情都会更有效。

如果您只有少量数据并且可以完全控制您的页面,那么请继续将数据放入数据属性和属性中。但不要存储大块或复杂结构。

哦,我不认为有任何性能问题 - 访问 DOM 中的元素及其属性可能不会比访问对象结构的某些部分更快或更慢,尽管我确信有更快和两种方式都比较慢。

【讨论】:

    【解决方案3】:

    我认为在 DOM 中存储数据没有任何错误,但我认为问题在于在 DOM 中存储大量数据。浏览器确实必须通过 DOM 来输出我们看到的页面,并且其中的数据越多,它需要整理的垃圾就越多。

    我相信还有其他原因,这只是我的推论。

    【讨论】:

    • 我明白浏览器必须通过 DOM 来显示页面,但是当页面渲染后添加数据属性时,这仍然适用吗?对数据属性的更改会触发重绘吗?
    • @DustMason 就像 mkoryak 所说,在 DOM 中存储和检索事物会降低性能,这就是为什么您不应该将其用作数据库的原因。多个 IO 操作可能会降低您的应用速度
    【解决方案4】:

    在为浏览器功能有限的 CE 设备开发了一些单页应用程序之后,我对这些事情采用了一些额外的个人标准。主要的是,仅仅因为 JQuery 支持扫描 DOM,这并不意味着它是一种高性能的方法。如果我需要知道哪个 LI 有焦点,我可以使用 .index() 或 .find() 甚至 .each(),但是将这个值保存在单独的模型对象中会更好,原因如下:

    1. MVC 是一个真实的东西,尽管通过使用 DOM 作为状态持有者之类的事情来滥用猖獗。作为规则在模型中保持状态使 MVC 有意义。
    2. 扫描 LI 标记比在代码中使用 listItems.focussed 更昂贵。
    3. DOM 正忙于操作,您对它的查询可能会延迟或导致延迟。
    根据马特@https://github.com/Matt-Esch/virtual-dom, “读取一些 DOM 节点属性甚至会产生副作用。”我倾向于同意这一点,但我承认我正在寻找更多关于这一点的证据,因为我个人认为被任命追查我们最大的应用程序性能问题的人主要与 DOM 相关的代码有关。

    【讨论】:

    • 关于读取节点的副作用:phpied.com/rendering-repaint-reflowrelayout-restyle 参见“浏览器很聪明”部分。我自己也是一个追求性能问题的人,我记得旧的 IE 在这件事上真的很奇怪。 Dynatrace ajax 版本对于帮助理解那里发生的事情非常宝贵。
    猜你喜欢
    • 2015-07-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多