Side navigation
#14304 closed bug (notabug)
Opened August 26, 2013 02:57PM UTC
Closed November 04, 2013 05:39PM UTC
Event in mouseenter handler is mutable (may change in deferred handler)
Reported by: | Victor Homyakov <vkhomyackov@gmail.com> | Owned by: | |
---|---|---|---|
Priority: | low | Milestone: | None |
Component: | event | Version: | 2.0.3 |
Keywords: | Cc: | ||
Blocked by: | Blocking: |
Description
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).
Attachments (0)
Change History (4)
Changed August 26, 2013 03:48PM UTC by comment:1
component: | unfiled → event |
---|---|
priority: | undecided → low |
status: | new → open |
version: | 1.9.1 → 2.0.3 |
Changed August 26, 2013 03:57PM UTC by comment:2
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).
Changed October 29, 2013 02:24PM UTC by comment:3
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.
Changed November 04, 2013 05:39PM UTC by comment:4
resolution: | → notabug |
---|---|
status: | open → closed |
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.
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 asetTimeout
) 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!