- jQuery Design Patterns
- Thodoris Greasidis
- 843字
- 2021-07-16 12:52:27
Introducing the Delegated Event Observer Pattern
Now that we have learned some advanced details about how to use the Observer Pattern using jQuery, we will get introduced to a special variation of it that fits perfectly to the web platform and provides some extra benefits. The Delegated Event Observer Pattern (or simply Delegate Observer Pattern) is often used in web development and it utilizes the bubbling feature that most events that are fired on DOM elements have. For example, when we click on a page element, the click event is immediately fired on it, and right after this it also fires on all its parent elements until it reaches the root of our HTML document. Using a slightly different overloaded version of the jQuery's $.fn.on
method, we can easily create and attach observers on page elements for delegated events that are fired on specific child elements.
Note
The term "Event Delegation" describes the programming pattern where the handler of an event is not attached directly to the element of interest, but is instead attached to one of its ancestor elements.
How it simplifies our code
Reimplementing our dashboard example using the Delegated Event Observer Pattern will require us to change only the code of the included JavaScript file to the following:
$(document).ready(function() { $('#categoriesSelector').change(function() { var $selector = $(this); var selectedIndex = +$selector.val(); var $dashboardCategories = $('.dashboardCategory'); var $selectedItem = $dashboardCategories.eq(selectedIndex).show(); $dashboardCategories.not($selectedItem).hide(); }); $('.dashboardCategories').on('click', 'button', function() { var $button = $(this); var boxHtml = '<p class="boxsizer"><article class="box">' + '<header class="boxHeader">' + $button.text() + '<button class="boxCloseButton">✖' + '</button>' + '</header>' + 'Information box regarding ' + $button.text() + '</article></p>'; $('.boxContainer').append(boxHtml); }); $('.boxContainer').on('click', '.boxCloseButton', function() { $(this).closest('.boxsizer').remove(); }); });
The most obvious difference is that the new implementation is shorter. The benefits come by defining just one observer to a common ancestor element, for each action that applies to more than one page element. For this reason, we use the $.fn.on(events, selector, handler)
overload variation of the $.fn.on()
method.
Specifically, we add an observer to the page element with the dashboardCategories
CSS class and listen for the click
events that originate from any of its <button>
descendants. Similarly, we add a single observer to the boxContainer
element that will be executed whenever a click event fires on any of its descendants that match the .boxCloseButton
CSS selector.
Since the above observers apply not only to the elements that existed in the page at the moment they were registered, but also to any element that is added at any later point of time and matches the specified CSS selector; we are able to decouple the code that handles the clicks on the close buttons and place it in a separate observer, instead of registering a new one every time a new information box is added. As a result, the observer that adds the new information boxes in the dashboard is simpler and only has to deal with creating the HTML of the box and insert it into the dashboard, leading to a greater separation of concerns. Moreover, we no longer need to handle the registration of the observer for the close button of the hint box in a separate piece of code.
Compare the memory usage benefits
We will now compare the difference in memory usage when using the $.fn.on()
method with the simple and Delegated Event Observer Pattern variation. To achieve this we will open the two implementations of our dashboard example and compare their memory usage on Chrome. To open Chrome's developer tools, just press F12 and then navigate to the Timeline tab. We press the "record" button in the Chrome's Timeline tab and then press each category item button 10 times, resulting in the addition of 120 information boxes to our dashboard. After adding all the boxes, we end up with 121 open boxes in total, since the hint box will still be open and then stop the timeline recording.
The results in the timeline for our initial Observer Pattern implementation will look as follows:

Repeating the same process for the Delegated Event Observer Pattern implementation will give a smoother timeline, revealing less object allocations and Garbage Collections, as follows:

As you can see in the preceding images, we end up with 1192 page elements in both cases, but in the first implementation we are using 134 event listeners, as compared to the implementation with event delegation where we initially created three event listeners and never actually added another.
Finally, as you can see from the blue line in the graph, the memory consumption of the delegate version stayed relatively the same, adding up to just around 200 KB. On the other hand, in the original implementation, the heap size increased more than five times, gaining more than 1 MB of increase.
Adding so many elements may not be an actual use case, but the dashboard will probably not be the only dynamic part of your page. As a result, in a relatively complex web page, we could get similar improvements if we reimplemented every applicable part of it using the Delegated Event Observer Pattern variant.
- Python for Secret Agents:Volume II
- JavaScript+jQuery網頁特效設計任務驅動教程(第2版)
- 機器人Python青少年編程開發實例
- Mastering C# Concurrency
- Apache Mesos Essentials
- Linux命令行與shell腳本編程大全(第4版)
- 青少年學Python(第1冊)
- 深入淺出React和Redux
- Java Web開發就該這樣學
- Android驅動開發權威指南
- Go語言編程
- Arduino Wearable Projects
- Mastering Adobe Captivate 7
- 零基礎看圖學ScratchJr:少兒趣味編程(全彩大字版)
- 基于GPU加速的計算機視覺編程:使用OpenCV和CUDA實時處理復雜圖像數據