Skip to main content

Bug Tracker

Side navigation

#14960 closed bug (migrated)

Opened April 03, 2014 12:07PM UTC

Closed October 21, 2014 12:37AM UTC

contents and children selectors can return elements out of order

Reported by: npben Owned by: gibson042
Priority: high Milestone: 1.12/2.2
Component: traversing Version: 1.11.0
Keywords: Cc:
Blocked by: Blocking:
Description

This problem exists in version 1.11.0.

I looked into source since the children and content selectors are just hardcoded not go into the logic that verifies uniqueness, it is probably just a situation that wasn't considered.

Examples are here for children() and here for contents().

Removing these two tags from the guaranteedunique array fixes the issue, but I didn't make a patch because I'm not familiar with the source and there may be a better way to handle it.

Workaround: calling $().add(unorderedobject) causes the uniqueness check to sort the elements.

Attachments (0)
Change History (7)

Changed April 03, 2014 12:28PM UTC by scottgonzalez comment:1

status: newopen

The uniqueness check doesn't run for children because we assume that the elements are already in order, so getting children will always result in an ordered set. But you've shown a scenario where that assumption is incorrect: A set containing a descendant of another element in the set.

Changed April 03, 2014 12:30PM UTC by scottgonzalez comment:2

component: unfiledtraversing

The uniqueness check was removed due to #7964.

Changed April 30, 2014 01:12PM UTC by dmethvin comment:3

milestone: None1.12/2.2
priority: undecidedhigh

We can still avoid the uniqueness overhead for single-element sets as we currently do, but it seems like the whole optimization added in #7964 for multi-element sets may have to be backed out if there is no way to recognize this case.

Changed April 30, 2014 06:04PM UTC by dmethvin comment:4

This test case shows it a little more clearly on the console: http://jsfiddle.net/sfMr2/7/

Changed May 12, 2014 11:02PM UTC by reavowed comment:5

I've had a bit of a look at the problem and potential solutions, and figured I'd share my thoughts in case they're useful to anyone.

The problem is (as identified above) that while .children() and .contents() preserve uniqueness, they do not necessarily preserve ordering of a sequence, if that sequence contains nested elements.

Checking that a sequence contains no nested elements is probably costly, especially if you then further have to run $.unique over the children() anyway. However, under the assumption that the source sequence is ordered, there is a much more efficient way of checking / resorting. It uses the fact that if A < B, then A cannot be a descendant of B. Further, if A < B < C and B is not a descendant of A, then C cannot be a descendant of A either. So, the following algorithm will calculate the children of a sequence of elements while keeping the results ordered, in a single pass iteration:

  • Take the first element from the source sequence (call it A), and calculate its children.
  • Get more elements from the source sequence, for as long as they are descendants of A.
  • If no descendants were found, push the children of A to the result sequence.
  • If one or more descendants were found, push their children into an array with the children of A, run $.unique on this array, and push it to the result sequence.
  • Repeat with the next element in the sequence.

This should only run $.unique on those sets of child elements which we can't reasonably confirm are kept in order, while requiring at most (n-1) additional $.contains() calls. It's not a particularly complicated algorithm either, though I don't know enough about jQuery's NFRs to say whether it's worth adding as a special case, rather than the simpler solution of applying $.unique naively.

I would however definitely recommend renaming "guaranteedUnique" to something more specific like "preservesUniquenessAndOrder". It's a shame that jQuery.unique isn't named a bit more sensibly as well (Sizzle at least calls the function uniqueSort).

Changed July 28, 2014 04:27PM UTC by gibson042 comment:6

owner: → gibson042
status: openassigned

Changed October 21, 2014 12:37AM UTC by m_gol comment:7

resolution: → migrated
status: assignedclosed