Changeset 172396 in webkit
- Timestamp:
- Aug 11, 2014 11:10:25 AM (10 years ago)
- Location:
- trunk
- Files:
-
- 5 added
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r172381 r172396 1 2014-08-11 Brian J. Burg <burg@cs.washington.edu> 2 3 Web Inspector: Add a helper to avoid leaking single-fire event listeners in Promise chains 4 https://bugs.webkit.org/show_bug.cgi?id=135772 5 6 Reviewed by Timothy Hatcher. 7 8 * inspector/event-listener-expected.txt: Added. 9 * inspector/event-listener-set-expected.txt: Added. 10 * inspector/event-listener-set.html: Added. 11 * inspector/event-listener.html: Added. 12 1 13 2014-08-10 Oliver Hunt <oliver@apple.com> 2 14 -
trunk/Source/WebInspectorUI/ChangeLog
r172379 r172396 1 2014-08-11 Brian J. Burg <burg@cs.washington.edu> 2 3 Web Inspector: Add a helper to avoid leaking single-fire event listeners in Promise chains 4 https://bugs.webkit.org/show_bug.cgi?id=135772 5 6 Reviewed by Timothy Hatcher. 7 8 A common pattern when working with promise chains is to convert an event 9 handler into a promise by using a single-fire event listener with the 10 resolve continuation as the callback. This is fine if the event fires; 11 if it doesn't fire, then the event emitter permanently keeps a reference to the 12 this-object and the callback. 13 14 This patch adds EventListener, a proxy object for events that can be manipulated 15 from multiple promise callback functions. If a promise is rejected, the catch 16 block can disconnect any event listeners set up earlier in the promise chain. 17 18 This patch also reimplements EventListenerSet to use multiple EventListeners, 19 since they share the same logic to uniformly handle Inspector and DOM events. 20 21 Test: inspector/event-listener.html 22 Test: inspector/event-listener-set.html 23 24 * UserInterface/Base/EventListener.js: Added. 25 (WebInspector.EventListener): 26 (WebInspector.EventListener.prototype.this._callback): 27 (WebInspector.EventListener.prototype.connect): 28 (WebInspector.EventListener.prototype.disconnect): 29 * UserInterface/Base/EventListenerSet.js: Update license block. 30 (WebInspector.EventListenerSet.prototype.register): 31 (WebInspector.EventListenerSet.prototype.install): 32 (WebInspector.EventListenerSet.prototype.uninstall): 33 * UserInterface/Main.html: Include EventListener. 34 * UserInterface/Test.html: Include EventListener and EventListenerSet. 35 1 36 2014-08-10 Timothy Hatcher <timothy@apple.com> 2 37 -
trunk/Source/WebInspectorUI/UserInterface/Base/EventListenerSet.js
r164543 r172396 1 1 /* 2 * Copyright (C) 2013 University of Washington. All rights reserved.2 * Copyright (C) 2013, 2014 University of Washington. All rights reserved. 3 3 * Copyright (C) 2014 Apple Inc. All rights reserved. 4 4 * … … 12 12 * documentation and/or other materials provided with the distribution. 13 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS15 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED16 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A17 * P ARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT18 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,19 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT20 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY22 * THEORYOF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. … … 39 39 40 40 WebInspector.EventListenerSet.prototype = { 41 register: function(emitter, type, listener, thisObject, useCapture)41 register: function(emitter, type, callback, thisObject, usesCapture) 42 42 { 43 console.assert(listener, "Missing listener for event: " + type); 44 console.assert(emitter, "Missing event emitter for event: " + type); 45 console.assert(emitter instanceof WebInspector.Object || emitter instanceof Node || (typeof emitter.addEventListener === "function"), "Event emitter", emitter, " (type:" + type + ") does not implement Node or WebInspector.Object!"); 43 console.assert(callback, "Missing callback for event: " + type); 44 console.assert(type, "Tried to register listener for unknown event: " + type); 45 var emitterIsValid = emitter && (emitter instanceof WebInspector.Object || emitter instanceof Node || (typeof emitter.addEventListener === "function")); 46 console.assert(emitterIsValid, "Event emitter ", emitter, " (type:" + type + ") is null or does not implement Node or WebInspector.Object!"); 46 47 47 if ( emitter instanceof Node)48 listener = listener.bind(thisObject || this._defaultThisObject);48 if (!emitterIsValid || !type || !callback) 49 return; 49 50 50 this._listeners.push({ emitter: emitter, type: type, listener: listener, thisObject: thisObject, useCapture: useCapture});51 this._listeners.push({listener: new WebInspector.EventListener(thisObject || this._defaultThisObject), emitter: emitter, type: type, callback: callback, usesCapture: usesCapture}); 51 52 }, 52 53 … … 61 62 { 62 63 console.assert(!this._installed, "Already installed listener group: " + this.name); 64 if (this._installed) 65 return; 63 66 64 67 this._installed = true; 65 68 66 for (var listenerData of this._listeners) { 67 if (listenerData.emitter instanceof Node) 68 listenerData.emitter.addEventListener(listenerData.type, listenerData.listener, listenerData.useCapture); 69 else 70 listenerData.emitter.addEventListener(listenerData.type, listenerData.listener, listenerData.thisObject || this._defaultThisObject); 71 } 69 for (var data of this._listeners) 70 data.listener.connect(data.emitter, data.type, data.callback, data.usesCapture); 72 71 }, 73 72 … … 75 74 { 76 75 console.assert(this._installed, "Trying to uninstall listener group " + this.name + ", but it isn't installed."); 76 if (!this._installed) 77 return; 77 78 78 79 this._installed = false; 79 80 80 for (var listenerData of this._listeners) { 81 if (listenerData.emitter instanceof Node) 82 listenerData.emitter.removeEventListener(listenerData.type, listenerData.listener, listenerData.useCapture); 83 else 84 listenerData.emitter.removeEventListener(listenerData.type, listenerData.listener, listenerData.thisObject || this._defaultThisObject); 85 } 81 for (var data of this._listeners) 82 data.listener.disconnect(); 86 83 87 if (unregisterListeners) {84 if (unregisterListeners) 88 85 this._listeners = []; 89 delete this._defaultThisObject;90 }91 86 }, 92 87 } -
trunk/Source/WebInspectorUI/UserInterface/Main.html
r171790 r172396 166 166 167 167 <script src="Base/DOMUtilities.js"></script> 168 <script src="Base/EventListener.js"></script> 168 169 <script src="Base/EventListenerSet.js"></script> 169 170 <script src="Base/ImageUtilities.js"></script> -
trunk/Source/WebInspectorUI/UserInterface/Test.html
r166040 r172396 36 36 37 37 <script src="Base/DOMUtilities.js"></script> 38 <script src="Base/EventListener.js"></script> 39 <script src="Base/EventListenerSet.js"></script> 38 40 <script src="Base/URLUtilities.js"></script> 39 41 <script src="Base/Utilities.js"></script>
Note: See TracChangeset
for help on using the changeset viewer.