Bug Tracker

Opened 10 years ago

Closed 10 years ago

#14304 closed bug (notabug)

Event in mouseenter handler is mutable (may change in deferred handler)

Reported by: Victor Homyakov <vkhomyackov@…> Owned by:
Priority: low Milestone: None
Component: event Version: 2.0.3
Keywords: Cc:
Blocked by: Blocking:


When using setTimeout() or _.throttle() (from Underscore.js) in mouseenter event handler in Chrome, then you might note that some properties of event object may change after timeout (e.g. event.type or event.delegateTarget - look at https://github.com/jquery/jquery/blob/master/src/event.js#L363 - it seems that jQuery reuses the same event object in event simulation).

Example at jsfiddle: http://jsfiddle.net/Qtkuh/ Move mouse into Result area, and you will note that deferred handler receives event with changed field type.

The fact that event object is mutable (or reused) isn't stated in documentation. This leads to hardly reproducible and understandable errors when someone tries to create asynchronous event handlers (any error in asynchronous code is hard to find).

Change History (4)

comment:1 Changed 10 years ago by dmethvin

Component: unfiledevent
Priority: undecidedlow
Status: newopen

This has been true for many versions now, perhaps as far back as jQuery 1.4. I suspect the reason it has never been reported is that using the native IE event object outside the handler chain (for example in a setTimeout) throws errors in IE 6-8. The object is automatically destroyed at the end of the event delivery cycle, leaving an invalid reference inside jQuery's Event object. Plugins like hoverIntent copy the information they need rather than trying to save a reference to the entire event object, which circumvents both that problem and the one you've described here.

It's much too costly to create a new object and copy over all the properties in these potentially high-frequency events, which is why the existing object is re-used. However, it seems like we could save and restore the properties we change, and I thought it already did this (at least for type).

I'll mark this open for investigation; if you'd like to look at the code to find the problem spots it would be greatly appreciated!

comment:2 Changed 10 years ago by Victor Homyakov <vkhomyackov@…>

I've already mentioned one problem spot, where delegateTarget (used in my deferred handler) is changed: https://github.com/jquery/jquery/blob/master/src/event.js#L363

At this line delegateTarget is overwritten when synchronous processing of mouseenter event is done (right before mouseover event).

comment:3 Changed 10 years ago by gibson042

Changes in delegateTarget, like currentTarget, are to be expected over the course of event propagation (see http://api.jquery.com/event.delegateTarget/). type mutation is potentially a much more sticky issue, but it seems to me like we're already following the most reasonable course of action by reverting it after propagation has completed.

comment:4 Changed 10 years ago by dmethvin

Resolution: notabug
Status: openclosed

Agreed. If you want a snapshot of the event as it appeared in the handler, you'll need to bear the overhead of a full copy. Be careful because the event may have cyclical references.

Note: See TracTickets for help on using tickets.