19

我有一些这样的标记(类仅用于说明):

<ol id="root" class="sortable">
  <li>
    <header class="show-after-collapse">Top-Line Info</header>
    <section class="hide-after-collapse">
      <ol class="sortable-connected">
        <li>
          <header class="show-after-collapse">Top-Line Info</header>
          <section class="hide-after-collapse">
            <div>Content A</div>
          </section>
        </li>
      </ol>
    </section>
  </li>
  <li>
    <header/>
    <section class="hide-after-collapse">
      <ol class="sortable-connected">
        <li>
          <header/>
          <section class="hide-after-collapse">
            <div>Content B</div>
          </section>
        </li>
      </ol>
    </section>
  </li>
</ol>

也就是说,嵌套的可排序列表。然而,可排序插件就足够了,因为每个 li(以下称为“项目”)都保持其级别,尽管内部列表是连接的。这些项目有一个始终可见的标题和一个在展开状态时可见的部分,通过单击标题进行切换。用户可以随意添加和删除任一级别的项目;添加顶级项目将在其中包含一个空的嵌套列表。我的问题是关于新创建项目的 JS 初始化:虽然它们将共享一些通用功能,但我可以通过

$("#root").on("click", "li > header", function() {
  $(this).parent().toggleClass("collapsed");
});

li.collapsed section {
  display: none;
}

(附带问题:这是否是使用详细信息/摘要 HTML5 标记的合适位置?关于这些是否会进入最终规范似乎有点不确定,我想要一个滑动过渡,所以看起来我会无论如何都需要JS。但我把这个问题抛给大众。你好,大众。)

如果根列表是保证在页面加载时存在的唯一(相关)元素,为了 .on() 有效地工作,我必须将所有事件绑定到该元素并为每个元素拼出精确的选择器,因为我明白它。因此,例如,要将单独的功能绑定到彼此相邻的两个按钮,我必须每次都完整地拼出选择器,à la

$("#root").on("change", "li > section button.b1", function() {
  b1Function();
}).on("change", "li > section button.b2", function() {
  b2Function();
});

那准确吗?既然如此,在将新项目添加到页面时放弃 .on() 并绑定我的事件是否更有意义?如果这会对响应产生影响,那么项目的总数最多可能会达到几十个。

4

2 回答 2

44

您将在绑定事件时创建更少的 CPU 开销,$(<root-element>).on(<event>, <selector>)因为您将绑定到单个“根”元素,而不是可能更多的单个后代元素(每个绑定都需要时间......)。

话虽如此,当实际事件发生时,您将产生更多的 CPU 开销,因为它们必须将 DOM 冒泡到“根”元素。

短篇故事: delegate 在绑定事件处理程序时节省 CPU ;当事件触发(例如,用户点击某物)时,bind 会节省 CPU 。

因此,由您决定哪一点对性能更重要。添加新元素时是否有可用的 CPU?如果是这样,那么直接绑定到新元素将是整体性能的最佳选择,但是如果添加元素是 CPU 密集型操作,您可能希望委托事件绑定并让事件触发从所有冒泡中产生一些额外的 CPU 开销。

注意:

$(<root-element>).on(<event>, <selector>, <event-handler>)

是相同的:

$(<root-element>).delegate(<selector>, <event>, <event-handler>)

然后:

$(<selector>).on(<event>, <event-handler>)

是相同的:

$(<selector>).bind(<event>, <event-handler>)

.on()是 jQuery 1.7 中的新功能,如果您使用的是 1.7+,那么.delegate(<selector>, <event>, <event-handler>)它只是.on(<event>, <selector>, <event-handler>).

更新

这是一个性能测试,表明委托事件绑定比单独绑定到每个元素更快:http: //jsperf.com/bind-vs-click/29可悲的是,此性能测试已被删除。

更新

这是一个性能测试,表明当您直接绑定到元素而不是委托绑定时,事件触发更快:http: //jsperf.com/jquery-delegate-vs-bind-triggering(请注意,这不是一个完美的性能测试,因为绑定方法包含在测试中,但是由于delegate绑定时运行速度更快,这意味着bind在谈论触发时相对更快)

于 2012-01-11T22:19:00.060 回答
14

由于接受的答案有不准确的测试(顺便说一句:测试你的代码,测量性能,不要盲目地遵循一些“规则” ——这不是优化的完成方式!)而且完全是错误的,我发布了固定测试: https:// jsperf.com/jquery-delegate-vs-bind-triggering/49

这证明在这样一个简单的例子中委托或直接绑定之间没有区别

委托总是不好的唯一情况是鼠标移动和滚动之类的事件-每秒触发 x 次。这是您会注意到任何性能差异的地方。

如果您在单个事件(例如单击)上甚至有 1 毫秒的差异(不会发生,但这只是一个示例),您将不会注意到这一点。如果您对每秒发生 100 次的事件有 1 毫秒的差异 - 您会注意到 CPU 消耗。

仅仅拥有数千个元素不会对委托的性能产生负面影响 - 实际上 - 应该使用它们 - 以避免在附加数千个事件处理程序时占用 CPU。

因此,如果您确实需要遵循规则(不要那样做) - 对除鼠标移动、滚动和其他您可以预期连续触发的事件之外的所有事件使用委托。

于 2015-12-25T16:26:29.460 回答