What's the difference between queryAll and querySelectorAll
Asked Answered
P

2

16

The definitions from the DOM Standard seems almost exactly the same, and I don't understand the difference.

What is the difference between queryAll and querySelectorAll.

The evaluation logic from DOM standard is below, but I am not smart enough to understand it.

query & queryAll

To match a relative selectors string relativeSelectors against a set, run these steps:

Let s be the result of parse a relative selector from relativeSelectors against set. [SELECTORS]

If s is failure, throw a JavaScript TypeError.

Return the result of evaluate a selector s using :scope elements set. [SELECTORS]

The query(relativeSelectors) method must return the first result of running match a relative selectors string relativeSelectors against a set consisting of context object, and null if the result is an empty list.

The queryAll(relativeSelectors) method must return an Elements array initialized with the result of running match a relative selectors string relativeSelectors against a set consisting of context object.

querySelector & querySelectorAll

To scope-match a selectors string selectors against a node, run these steps:

Let s be the result of parse a selector selectors. [SELECTORS]

If s is failure, throw a JavaScript TypeError.

Return the result of evaluate a selector s against node's root using scoping root node and scoping method scope-filtered. [SELECTORS].

The querySelector(selectors) method must return the first result of running scope-match a selectors string selectors against the context object, and null if the result is an empty list otherwise.

The querySelectorAll(selectors) method must return the static result of running scope-match a selectors string selectors against the context object.

Preternatural answered 24/4, 2014 at 13:4 Comment(0)
N
10

query() and queryAll() accept a relative selector string, whereas querySelector() and querySelectorAll() do not. A relative selector is basically a selector which may be partial and start with a combinator:

var parentNode = document.getElementById('parentNode'); // document.querySelector('#parentNode');

// Find .childNode elements that are direct descendants (children) of parentNode
// This cannot be done with querySelectorAll() using the existing reference to parentNode
parentNode.queryAll('> .childNode');
// querySelectorAll does allow getting all descendants of parentNode though
parentNode.querySelectorAll('.childNode');

But more importantly, queryAll() returns a live Elements[] array whereas the NodeList returned by querySelectorAll() is static, which means the nodes in that list are not updated when changes are made to their respective DOM elements.

In terms of their functionality, query() and queryAll() may be more analogous to find() and findAll(), defined in Selectors API level 2 — where you'll also find the definition of a relative selector — as both method groups accept and work with relative selectors. Note that findAll() also returns a static NodeList, so they are still not completely identical.

Nicolasanicolau answered 24/4, 2014 at 13:14 Comment(9)
It's also important to add what each function returns. One returns an Elements array, which contains live nodes and the other returns a static NodeList.Cumulous
@OozeMeister: Good point. That's also what makes queryAll() different from findAll(). I'll edit my answer.Nicolasanicolau
Thanks for the explanation. Note that the current polyfill barberboy/dom-elements for query() & queryAll() does not support relative selectors. jsbin & github issuePreternatural
Update: barderboy/dom-elements now supports relative selectors! jsbinPreternatural
This should probably be a separate question entirely, but why are there specs for both query[All] and find[All] if they are so close? Are they competing specs or are both likely to be implemented?Ioab
@Nathan Bubna: Good question. Actually, it was decided some time prior to my answer that Selectors API would be merged into DOM4; I did not notice this note in the Selectors API 2 spec until recently. I am not sure of the current fate of find[All].Nicolasanicolau
Actually parentNode.querySelectorAll(parentNode.nodeName + ' > .childNode'); is equivalent to parentNode.queryAll('> .childNode'); (except for the static/dynamic part).Mathildamathilde
@Nux: No, it's not. What that does is match .childNode elements with a parent that happens to have the same tag name as the parentNode reference, which doesn't at all imply that they're children of parentNode. For example, if parentNode is a div and its .childNode descendant is a child of another div that's nested inside it, such that the entire structure can be represented by the selector div#parentNode > div > .childNode, that statement would match that .childNode even though it is not a child of parentNode. The qSA equivalent is parentNode.querySelectorAll(':scope > .childNode');.Nicolasanicolau
@Nux: In any case, queryAll is gone now and I have no idea what to do with my answer. But thanks for the edit anyway.Nicolasanicolau
P
19

2016 Update

queryAll was removed from the DOM spec

Currently the most important difference between queryAll and querySelectorAll is that queryAll (as well as query) was removed from the DOM specification.

The current version of the DOM specification is available at:

Note: https://www.w3.org/TR/dom/ is an outdated fork of the DOM Standard (see Fork tracking on the WHATWG Wiki and the comment by Domenic for more info).

Last mention

The last version that included query and queryAll was published on 15 March 2016:

Removal

The next version doesn't mention query or queryAll anywhere:

Current specification

All occurances of query or queryAll in the DOM standard were commented out by Anne van Kesteren on March 29, 2016.

The current DOM specification (as of July 2016) doesn't mention query or queryAll at all:

querySelector and querySelectorAll are in section 4.2.6 Mixin ParentNode.

It seems that currently the only reliable API is querySelector and querySelectorAll (see this answer for more details) and according to this discussion on GitHub query and queryAll will not be available until the JavaScript subclassing of built-ins is implemented in the browsers and even then it will be unlikely to return a live Elements[] array as described in the answer by BoltClock.

Browser support

As of June 2016 there is no mention of query and queryAll on MDN:

On the other hand querySelector and querySelectorAll are well documented and widely supported:

Browser support of querySelector/querySelectorAll according to Can I use as of June 2016:

caniuse.com/queryselector (See: http://caniuse.com/queryselector for up to date info)

There is no info available on the support of query and queryAll.

More info

See also this answer for more info on the usage and browser support of querySelector and querySelectorAll.

Postbellum answered 7/7, 2016 at 12:35 Comment(6)
Your links are all to an outdated fork of the up-to-date DOM Standard at dom.spec.whatwg.org. For more information see wiki.whatwg.org/wiki/Fork_tracking. (We have repeatedly asked the W3C to stop copying and rebranding our specifications, but they have not.)Jerryjerrybuild
@Jerryjerrybuild Thanks for the info. I updated the answer so that all links now point to dom.spec.whatwg.org and I added a note on the outdated fork on w3c.org. I didn't know that the w3c fork is outdated. Thanks for pointing it out.Postbellum
@Domenic: I noticed the spec doesn't mention relative selectors at all. Are there any plans to allow querySelector and querySelectorAll to accept relative selectors? I'm glad the confusing new names have been removed entirely but I'm not a fan of having to prepend my drill-down selectors with :scope every time.Nicolasanicolau
@Domenic: Never mind - I figured out that making qSA accept relative selectors would break the current behavior (see element.querySelectorAll('E F') vs element.querySelectorAll(':scope E F')). I see now why the new methods were added in the first place...Nicolasanicolau
@Nicolasanicolau do I understand it correctly that qSA with a :scope placed at the beginning of the selector "fixes" the behavior, i.e. it behaves as one would expect (only selects descendants of element)?Devlen
@Nicolasanicolau you just made my day :)Devlen
N
10

query() and queryAll() accept a relative selector string, whereas querySelector() and querySelectorAll() do not. A relative selector is basically a selector which may be partial and start with a combinator:

var parentNode = document.getElementById('parentNode'); // document.querySelector('#parentNode');

// Find .childNode elements that are direct descendants (children) of parentNode
// This cannot be done with querySelectorAll() using the existing reference to parentNode
parentNode.queryAll('> .childNode');
// querySelectorAll does allow getting all descendants of parentNode though
parentNode.querySelectorAll('.childNode');

But more importantly, queryAll() returns a live Elements[] array whereas the NodeList returned by querySelectorAll() is static, which means the nodes in that list are not updated when changes are made to their respective DOM elements.

In terms of their functionality, query() and queryAll() may be more analogous to find() and findAll(), defined in Selectors API level 2 — where you'll also find the definition of a relative selector — as both method groups accept and work with relative selectors. Note that findAll() also returns a static NodeList, so they are still not completely identical.

Nicolasanicolau answered 24/4, 2014 at 13:14 Comment(9)
It's also important to add what each function returns. One returns an Elements array, which contains live nodes and the other returns a static NodeList.Cumulous
@OozeMeister: Good point. That's also what makes queryAll() different from findAll(). I'll edit my answer.Nicolasanicolau
Thanks for the explanation. Note that the current polyfill barberboy/dom-elements for query() & queryAll() does not support relative selectors. jsbin & github issuePreternatural
Update: barderboy/dom-elements now supports relative selectors! jsbinPreternatural
This should probably be a separate question entirely, but why are there specs for both query[All] and find[All] if they are so close? Are they competing specs or are both likely to be implemented?Ioab
@Nathan Bubna: Good question. Actually, it was decided some time prior to my answer that Selectors API would be merged into DOM4; I did not notice this note in the Selectors API 2 spec until recently. I am not sure of the current fate of find[All].Nicolasanicolau
Actually parentNode.querySelectorAll(parentNode.nodeName + ' > .childNode'); is equivalent to parentNode.queryAll('> .childNode'); (except for the static/dynamic part).Mathildamathilde
@Nux: No, it's not. What that does is match .childNode elements with a parent that happens to have the same tag name as the parentNode reference, which doesn't at all imply that they're children of parentNode. For example, if parentNode is a div and its .childNode descendant is a child of another div that's nested inside it, such that the entire structure can be represented by the selector div#parentNode > div > .childNode, that statement would match that .childNode even though it is not a child of parentNode. The qSA equivalent is parentNode.querySelectorAll(':scope > .childNode');.Nicolasanicolau
@Nux: In any case, queryAll is gone now and I have no idea what to do with my answer. But thanks for the edit anyway.Nicolasanicolau

© 2022 - 2024 — McMap. All rights reserved.