我正在尝试了解不显眼的 Javascript 的最佳实践。使用观察者的推荐且有效的方法是什么?

发布于 2024-10-18 10:27:57 字数 653 浏览 9 评论 0原文

我正在尝试了解不显眼的 Javascript 的最佳实践。 Unobtrusive Javascript 的想法之一是 Javascript 不应该直接包含在页面的 html 代码中,例如 onchange=runScript()。相反,应该创建一个观察者,以便在相关元素发生变化时执行代码。

我的问题是围绕观察者的最佳实践是什么。 Javascript 中的事件观察器有多少开销?

我不知道观察者在浏览器中通常是如何编码的。创建一个可以处理大量元素但必须为每次单击运行代码的单个通用观察者是否更有效,如下所示:

document.body.observe('click', function(event) {
  if (event.element().match('some_id')) {
    //do something
    event.stop()
  }
}

或者为每个与其非常匹配的相关元素创建一个观察者会更有效具体来说,如下所示:

$('some_id').observe('click', function(event) {
  //do something
  event.stop()
}

或者观察者的开销如此之低,根本没有理由担心它,我应该只做任何更方便编码的事情?

I'm trying to understand best practices for unobtrusive Javascript. Among the ideas of unobtrusive Javascript is that Javascript should not be directly included in the html code of the page, such as onchange=runScript(). Instead, an observer should be created to execute code whenever the element in question changes.

My questions are what the best practices are surrounding observers. How much overhead is there to an event observer in Javascript?

I don't know how observers are generally coded in browsers. Is it more efficient to create a single general observer that could handle a lot of elements but has to run code for each click, such as the following:

document.body.observe('click', function(event) {
  if (event.element().match('some_id')) {
    //do something
    event.stop()
  }
}

Or would it be more efficient to create a single observer for each relevant element that matches it very specifically, such as the following:

$('some_id').observe('click', function(event) {
  //do something
  event.stop()
}

Or are observers of such low overhead that there's no reason to worry about it at all, and I should just do whatever is more convenient to code?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

愚人国度 2024-10-25 10:27:57

虽然你在标题中写了 JavaScript,但我看到你在问题中使用了 jQuery。所以,希望以 jQuery 为中心的答案是可以的。

jQuery 包含两种方法来实现这一点:$.live()$.delegate()。当处理来自大量相关元素(例如大表的每一行)的事件时,使用事件委托绝对是一个好主意。将单个处理程序附加到表并在事件冒泡时捕获事件比将事件附加到每一行更有效。

对于单个元素(例如您的 ID 示例),事件委托不是必需的。一个简单的 $('#some_id').click(fn) 就可以了。

Though you wrote JavaScript in the title, I see you used jQuery in your question. So, hopefully a jQuery-centric answer is okay.

jQuery includes two ways to accomplish that, $.live() and $.delegate(). It's definitely a good idea to use event delegation when handling events from a large number of related elements (e.g. each individual row of a large table). Attaching a single handler to the table and catching events as they bubble up is more efficient than attaching an event to every single row.

For single elements (like your ID example), event delegation isn't necessary. A simple $('#some_id').click(fn) is fine.

待"谢繁草 2024-10-25 10:27:57

不合格的“高效”过于宽泛,不能说单一技术是最高效的。例如,存在时间效率和空间效率,并且两者之间通常需要进行权衡。此外,不同的浏览器可以自由地实现他们认为合适的事件,只要它们的行为符合 W3C 事件标准 规定,限制了关于时间和空间成本可以得出的结论。

我们可以分析与事件流相关的成本和效率。在每个兼容的浏览器中,事件首先在根元素上触发,然后在每个中间子元素上触发,直到到达目标,然后事件向上冒泡回到根,再次在中间元素上触发。在事件流期间,在文档结构中上下移动每一步都会产生时间成本(确定要触发哪个元素、查找侦听器等),因此如果您可以 在流程中尽早停止事件(如您的第一个例子)有可能节省时间。当然,对每个目标的特殊处理可能会抵消任何收益,并且提前停止事件可能是不正确的。

为每个元素集合创建单独但相等的侦听器函数可能会产生不必要的内存成本。请注意,这与在多个对象上订阅相同的函数不同。例如:

for (var i=0; i < elements.length; ++i) {
    elements[i].observe('click', function (evt) {...});
}

可能需要比以下更多的内存:

elements.each('click', function (evt) {...});

如果 JS 引擎 interns 运行,则两个将使用相同数量的内存。

我们不能假设的一件事是,在给定事件和元素的情况下如何查找事件侦听器。但是,给定事件和元素通常没有那么多侦听器,因此不应担心时间或空间效率。

最后,浏览器似乎能够很好地实现事件,因此性能差异往往不会成为问题。因此,简单性和可读性比如何定义和订阅事件侦听器更重要。

Unqualified, "efficient" is too broad to say that a single technique is the most efficient. For example, there's time efficiency and space efficiency, and there's often a tradeoff between the two. Also, different browsers are free to implement events however they see fit, as long as they behave as the W3C events standard dictates, limiting what conclusions can be made about time and space costs.

We can analyze costs and efficiencies in relation to event flow. In every compliant browser, an event first fires on the root element, then on each intervening child element until it reaches the target, then the event bubbles back up to the root, again firing on intervening elements. There will be a time cost in making each step down and up the document structure during event flow (figuring out which element to fire on, looking up the listeners &c.), so if you can stop an event as early as possible during flow (as in your first example) there is a potential time saving. Of course, special handling of each target may offset any gain and it may be incorrect to stop an event early.

Creating a separate but equal listener function for each of a collection of elements may produce an unnecessary memory cost. Note this is not the same thing as subscribing the same function on multiple objects. For example:

for (var i=0; i < elements.length; ++i) {
    elements[i].observe('click', function (evt) {...});
}

may require more memory than:

elements.each('click', function (evt) {...});

If the JS engine interns functions, the two will use the same amount of memory.

One thing we can't assume is how event listeners are looked up, given an event and element. However, there typically aren't that many listeners for a given event and element, so the time or space efficiency of this shouldn't be a concern.

In the end, browsers seem to implement events well enough that performance differences don't tend to be an issue. Simplicity and readability are thus more important than how you define and subscribe event listeners.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文