JS framework

G

Garrett Smith

Matt said:
[...]


Your solution may work, but I think a sane jQuery solution is even
better:

$li.nextAll('li').toggleClass('odd');
...^

what is $li?
Simple and efficient.

Relatively, it is not as inefficient, but it is far from ideal. You
don't need any selector API for that.

When a pattern applies to universally to descendants, it is more
efficient to let the browser handle the cascade and inheritance, rather
than do all that traversing manually.

To let the browser handle the cascade, change the class of the
containing element and define a rule for that in the stylesheet.

Example:
css:
..itemList .zebra{
background: #ffe;
}

..itemListRestriped .zebra{
background: #fff;
}

html:
<ul>
<li>
one
</li>
<li class="zebra">
two
</li>
<li>
three
</li>
<li class="zebra">
four
</li>
</ul>

By leting the browser apply the cascade in the stylesheet, the
javascript code is reduced to a couple of lines. No selector API needed:

Example:-
<!doctype html>
<html>
<head>
<title>Toggling Cascade</title>
<style type="text/css">
..zebra{
background: #ffd;
}

..itemListRestriped li {
background: #ffd;
}

..itemListRestriped .zebra{
background: #fff;
}

</style>
</head>
<body>
<ul id="itemList">
<li>
one
</li>
<li class="zebra">
two
</li>
<li>
three
</li>
<li class="zebra">
four
</li>
</ul>

<script type="text/javascript">

// TODO: Replace global var with object state property.
var isRestriped = false;

// TODO: refactor to object.
function restripe() {
var itemList = document.getElementById("itemList");

// TODO: use addClass/removeClass functions.
if(isRestriped) {
itemList.className = "";
} else {
itemList.className = "itemListRestriped";
}
isRestriped = !isRestriped;
}
</script>

<button type="button" onclick="restripe()">restripe()</button>

</body>
</html>

Garrett
 
T

Thomas 'PointedEars' Lahn

kangax said:
Thomas said:
kangax said:
Garrett Smith wrote:
Knowing how to use document.getElementById, event bubbling (also called
"delegation") would offer much superior runtime performance [than jQuery]
You can't do much with `document.getElementById`. Sometimes you want to
select by class, attribute, descendant or a combination of those. I
agree that more complex selectors are rarely needed (well, except maybe
something like `nth-child("odd")`).

Event delegation is great, but then you might want some kind of `match`
method to determine whether a target element matches selector. `match`
is not necessary, of course, but testing an element manually adds noise
and verbosity.
Iterating over all elements to add event listeners to all target elements
adds much more noise and unreliability. For universally bubbling events,

I never said anything about adding event listeners to elements being
iterated over. I stopped doing that a while ago in favor of event
delegation. Nevertheless, I still do iterate over elements (by class,
descendant, attribute, etc.) to perform certain action on them, such as
toggling visibility.

I suppose manipulating relevant stylesheet rules could achieve similar
result.

How do you do it?

By ID. It is the most efficient and compatible by far.
Verbosity has a tendency to add noise. Noise makes it hard to
understand, maintain and refactor code. That's all I meant.

Compare:

if (matches(element, '#sidebar .faq-section .toggle')) { ... };

vs. something like:

if (hasClass(element, 'toggle') &&
hasParentWithClass(element, '.faq-section') &&
hasParentWithId(element, 'sideabar')) { ... }

CSS syntax is concise and well-known. It's easy to understand and maintain.

But that is why one uses CSS for formatting and not scripting. For example,
if it is necessary to hide elements in a certain context on click, this
stylesheet fragment:

#sidebar .faq-section div.toggle.hidden {
display: none;
}

The only thing that needs to be in the client-side script now is changing
the `className' property of the event target to add/remove `hidden' if its
`className' property includes `toggle'.¹ BTDT (with mouseover and mouseout).


HTH

PointedEars
___________
¹ Meaning that the white-space separated list of the `className'
property/`class' attribute value contains or does not contain
said substring.
 
M

Matt Kruse

..^
what is $li?

Assumed to be a jQuery object referencing the LI element to be
removed.
Relatively, it is not as inefficient, but it is far from ideal.

Depends on how you define "ideal". In that it is short, easily
written, easy to understand, easy to debug, and fast enough under any
realistic usage situation, I would say it is as ideal as other
options.
You don't need any selector API for that.

True, but if jQuery is on the page already, you might as well use it.
I certainly wouldn't introduce jQuery into a page just to do this.
To let the browser handle the cascade, change the class of the
containing element and define a rule for that in the stylesheet.
Example:
css:
.itemList .zebra{
   background: #ffe;
}
.itemListRestriped .zebra{
   background: #fff;
}

That doesn't address the original problem or removing an element from
the list and having to re-apply the striping because your odd/even
distinctions have been messed up.

Of course, this is certainly best handled by using pure CSS alone, but
we're stilling living in a web where that's not practical for most.

Matt Kruse
 
M

Matt Kruse

Even IE5 understands div.toggle.hidden (IE4 doesn't, but who cares).

IE6 does not understand a rule like:

div.a.b { ... }

It treats it the same as:

div.b { ... }

Matt Kruse
 
R

RobG

What is it that you like so much about a live collection, the word
"live" in its name, or the fact that any items might get swapped by
the browser behind the scenes ?

The fact that you can get a reference to them once, then they
automatically update when the DOM changes.
Why don't you prefer to have a fixed,
static set of items, a snapshot of the state of things at a given
time, more so given that you can refresh it as needed ?

Because browser-native code will do that much, much faster that
javascript.

How do you pass a static collection to another method in a way that it
knows how to update it? You either have to create your own object
with an update method, the callee has to update it before passing it
or the receiving function has to make a guess about the parameter
being passed. Passing a live collection doesn't have all those
issues, it just has to deal with the collection knowing that at any
point in time it represents the actual DOM.

Because, while you can easily and for free make a static list "live"
just by re-fetching it

That isn't "free", nor live; and there are other issues (see below).
(that's what the browser does for you
automatically behind the scenes in a live collection),

You can only make that statement if you have read the actually
implementation of live collections in more than a couple of browsers.
Have you? It is just as likely that the browser caches the collection
and updates it whenever the DOM changes so it never "re-fetches" the
entire collection. Browsers have been dealing with live lists since
CSS 1 at least, the code should already be highly optimised and deal
with a changing DOM.

In any case, the browser will do it much more efficiently than
javascript.
the opposite
operation is more expensive as it requires duplicating the live list
into another, additional array.

Only if you want a static list. What is it that you like so much
about static lists? The only trick with live collections is if you
are adding or deleting items in a loop. If all collections are live,
then once you learn to do that, life is easy.

I think the supposed performance penalty of a live list is a furphy
put about by those who like static lists (possibly motivated by the
fact that current javascript implementations of qSA are static). On
the HTML 5 mailing list, one of the Firefox developers wrote in to say
that live lists are actually faster, because Firefox already creates
lots of them and has highly optimised code for doing so. Their static
lists would actually be live lists converted to static.
 
G

Garrett Smith

Matt said:
Assumed to be a jQuery object referencing the LI element to be
removed.


Depends on how you define "ideal". In that it is short, easily
written, easy to understand, easy to debug, and fast enough under any
realistic usage situation, I would say it is as ideal as other
options.


True, but if jQuery is on the page already, you might as well use it.
I certainly wouldn't introduce jQuery into a page just to do this.


That doesn't address the original problem or removing an element from
the list and having to re-apply the striping because your odd/even
distinctions have been messed up.

Solving the wrong problem doesn't help much, does it?

When the element is removed, loop through the remaining elements,
starting at that next sibling element.

jQuery.dir = function( elem, dir ){
var matched = [], cur = elem[dir];
while ( cur && cur != document ) {
if ( cur.nodeType == 1 )
matched.push( cur );
cur = cur[dir];
}
return matched;
};

I don't much like identifier name |dir|, but it would seem to accomplish
traversal of "parentNode", "nextSibling", and "previousSibling". I
rather think elementsFromNode( node, dir ) explains the intent a bit
more clearly.

The solution requires a double traversal, though, once to collect the
nodes, then once to iterate over the returned array.

Writing it out by hand would be more tedious, but could be more
efficient. If the logic occurred in a few spots, a Restriper that could
work with TR or LI would be another possible solution.
Of course, this is certainly best handled by using pure CSS alone, but
we're stilling living in a web where that's not practical for most.

Right. Selectors Level 3 ":nth-child" makes logical sense but it doesn't
work in IE.

Purely presentation stuff like that does not belong in javascript. It
should be possible without script. Not olnly avascript should not be
required for that to work, it is the wrong way to solve that problem.
Other options include not restriping, or a page refresh.

It seems the CSSWG has had a working draft for the ":nth-child" selector
since 2005[1]. Before that, :nth-child() was a candidate recommendation
in "Selectors", going back to 1999[2]. Four years seems like a long time
for a Working Draft status, and for that a proposal to get out the door,
ten years seems like a long time.

Since it is a working draft, Microsoft has a valid reason for not
implementing it[3][4].

IMO, the Selectors Level 3 working draft should be completed promptly
with a test suite for implementations to verify against.
[1]Selectors 2005: http://www.w3.org/TR/2005/WD-css3-selectors-20051215/
[2]Selectors 1999: http://www.w3.org/TR/1999/WD-CSS3-selectors-19990803
[3]IE Bugtracker:
https://connect.microsoft.com/IE/feedback/ViewFeedback.aspx?FeedbackID=445224&wa=wsignin1.0
[4]MSDN CSS Compatibility:
http://msdn.microsoft.com/en-us/library/cc351024(VS.85).aspx?ppud=4
 
G

Garrett Smith

Garrett said:
[...]


When the element is removed, loop through the remaining elements,
starting at that next sibling element.

jQuery.dir = function( elem, dir ){
var matched = [], cur = elem[dir];
while ( cur && cur != document ) {
if ( cur.nodeType == 1 )
matched.push( cur );
cur = cur[dir];
}
return matched;
};

I don't much like identifier name |dir|, but it would seem to accomplish
traversal of "parentNode", "nextSibling", and "previousSibling". I
rather think elementsFromNode( node, dir ) explains the intent a bit
more clearly.

The solution requires a double traversal, though, once to collect the
nodes, then once to iterate over the returned array.


Post post idea...

Performance coudl be improved by having elementsFromNode accepts a
callback function.

But then it would not have a return, so would want a new name. Like
iterateElementsFromNode.

Given a starting node, iteration iterates through element nodes in a
given direction, after |node|.

// untested.
function iterateElementsFromNode( node, dir, callback, context ) {
var n, i = 0, doc = node.ownerDocument;
for(n = node[dir]; n != null && n !== doc; n = n[dir]) {
if ( n.nodeType === 1 ) {
callback.call(context, n, i++);
}
}
}

// Sample callback would be something like:
function cb(n, i) {
var zebra = (i % 2 === 0) ? "even" : "odd";
document.writeln(n.tagName + ", ", i + ", " + zebra);
}

Simpler than using a selctors API.

Garrett
 
M

Matt Kruse

...
Simpler than using a selctors API.

That's still up to personal preference. I wrote working code in
literally about 10 seconds which does the exact same thing you are
trying to do with many lines of code and a few attempts.

In my mind, this is a demonstration of why libraries like jQuery are
useful and beneficial. IMO, the one-line, straight-forward jQuery
solution is by far the simplest. I'm not sure why you would consider
your example code simpler. But that's fine :)

Matt Kruse
 
R

RobG

Wow, what an uninformed "solution"! Where is that thread? I hope
better alternatives were offered.


Your solution may work, but I think a sane jQuery solution is even
better:

$li.nextAll('li').toggleClass('odd');

Sure, but clearly you know jQuery better than most. The first step is
to deternine a suitable algorithm for the solution (toggle the class
of subsequent LI siblings), then to implement it. I don't think any
library inherently creates "better" solutions as shown by the
"solution" offered above.

Is someone better off learning jQuery, or learning javascript - which
they are going to have to learn anyway if they have a future in web
development?

Simple and efficient.

But it isn't either. If it was simple, one of the posters in the
thread would have known it - jQuery doesn't give you the answer, it's
just a tool that can be used to implement a solution. It may be
efficient in terms of the time it takes someone experienced with
jQuery to write it versus someone experienced in javascript, however
it is certainly not efficient in terms of CPU usage. That may not be
an issue in a menu list of 10 items, but there are regular posters
talking about tables of 4,000 rows. It would be nice to see jQuery vs
POJS in that case.
 
J

Jorge

Because browser-native code will do that much, much faster that
javascript.

If the browser implements qSA() as native code, native code is what's
going to be executed in both cases (1). And, BTW, in the event that the
browser doesn't implement it natively, it can be easily implemented in
javascript for static lists, but *not* so for live collections: that
would *require* a getter...
How do you pass a static collection to another method in a way that it
knows how to update it? You either have to create your own object
with an update method, the callee has to update it before passing it
or the receiving function has to make a guess about the parameter
being passed. Passing a live collection doesn't have all those
issues, it just has to deal with the collection knowing that at any
point in time it represents the actual DOM.

Of course, but you wouldn't expect a static list to be live, would you ?
That isn't "free", nor live; and there are other issues (see below).


You can only make that statement if you have read the actually
implementation of live collections in more than a couple of browsers.
Have you?

For an experienced programmer like you that ought be so obvious (!).
Think about it again.
It is just as likely that the browser caches the collection
and updates it whenever the DOM changes so it never "re-fetches" the
entire collection. Browsers have been dealing with live lists since
CSS 1 at least, the code should already be highly optimised and deal
with a changing DOM.

A live collection is no more than a static list whose getters do a
refresh, an update, a re-build. Conceded that there's no need to refresh
it unless the "dirty bit" is set in the DOM tree. But a similar strategy
can be applied to static lists as well.
In any case, the browser will do it much more efficiently than
javascript.

See above (1).
Only if you want a static list. What is it that you like so much
about static lists? The only trick with live collections is if you
are adding or deleting items in a loop. If all collections are live,
then once you learn to do that, life is easy.

Life would be easier if you didn't have to walk around with tricks each
and every time. It's better to be able to command a refresh when a
refresh is what you need, than to have the browser command refreshes for
you unnecessarily or at arbitrary and often inconvenient times.
I think the supposed performance penalty of a live list is a furphy
put about by those who like static lists (possibly motivated by the
fact that current javascript implementations of qSA are static). On
the HTML 5 mailing list, one of the Firefox developers wrote in to say
that live lists are actually faster, because Firefox already creates
lots of them and has highly optimised code for doing so. Their static
lists would actually be live lists converted to static.

Both take as long to build the first time a certain query is made, and
subsequent updates can be optimized equally in both cases.
 
M

Matt Kruse


I see that someone else replied with a solution similar to mine, thank
goodness.
Sure, but clearly you know jQuery better than most.  The first step is
to deternine a suitable algorithm for the solution (toggle the class
of subsequent LI siblings), then to implement it.  I don't think any
library inherently creates "better" solutions as shown by the
"solution" offered above.

I most certainly agree. jQuery provides tools. An uninformed developer
can take any tool and create something terrifying! :)

Some say that jQuery provides the tools in a way that almost
encourages misuse, and I'm inclined to agree in many areas. Which is
why I'm pretty specific about who I think should use jQuery and under
what circumstances.

As it applies to the topic at hand, I would say:

1. The developer should have a good understanding of CSS/JS before
even facing this problem

2. The algorithm is independent of the coding and should be easily
found by a developer with moderate experience and logical thinking.

3. The developer should be familiar enough with jQuery to know the
range of tools it provides. I consulted my cheat sheet to find the
name of the nextAll() method because I didn't remember the name,
having never used it before, AFAIK. But I knew the functionality
existed because I have a broad view of the library.

4. The developer should hopefully be experienced enough to look at the
longer proposed solution and know that something is fishy in there,
and it could be simplified. But the ability to "sense" the opportunity
for optimization it something that is learned with time and
experience.

5. The developer should have enough experience to know that this
solution will be efficient enough for most cases. But jQuery starts to
break down when asked to do too much, so if performance suffers, the
developer should have enough js experience to recognize this, rip out
the jQuery code, and replace it with POJS.

It's unfortunate that many developers lack the skills to properly
understand all these points. And it's unfortunate that so many people
are looking to "learn jQuery" because POJS is "too hard".
Is someone better off learning jQuery, or learning javascript - which
they are going to have to learn anyway if they have a future in web
development?

Two posts in the jQuery group recently are typical of the mindset that
is troubling, IMO.

One was looking for jQuery books because they wanted to learn jQuery
before learning javascript. Cart. Horse. The other said that
javascript is "voodoo" to them, so they were complaining about
implementing the datePicker and not understanding the _javascript_
required! Shocking!

This kind of thing is typical of any tool that tries to bring a
sufficiently complicated technology to the masses, though.

Years ago, people figured out how to beam signals through the air,
build devices to capture these invisible signals, amplify them with
electricity, and use them to control a gun firing millions of
electrons into a screen to show 29.97 pictures per second and simulate
a moving image. Very complex technology brought into the living room
of the masses, yet decades later people still can't figure out their
remote control. Typical.
it is certainly not efficient in terms of CPU usage.  That may not be
an issue in a menu list of 10 items, but there are regular posters
talking about tables of 4,000 rows.  It would be nice to see jQuery vs
POJS in that case.

Indeed, many users wielding the jQuery hammer only see nails. I have
ripped out jQuery code and replaced it with POJS more times than I
care to count.

As I said to a fellow developer yesterday... "jQuery provides
convenience, not power. Don't confuse the two."

Matt Kruse
 
R

RobG

If the browser implements qSA() as native code, native code is what's
going to be executed in both cases (1). And, BTW, in the event that the
browser doesn't implement it natively, it can be easily implemented in
javascript for static lists, but *not* so for live collections: that
would *require* a getter...

The point is that if the choice is only one or the other, I'd prefer
to have live lists and convert them to static using JS than having
static lists that I have to update every time I use them to imitate
live lists. One suggestion on the HTML 5 list was to have both live
and static collections, either as separate methods or using a
parameter. To me that would be the best solution.

[...]
For an experienced programmer like you that ought be so obvious (!).

So you haven't.

Think about it again.

Unless you provide new information, the I'll reach the same conclusion
(to do otherwise would be illogical). There are dozens of ways to
implement particular functions, 5 or 10 will be equivalent for
criteria such as performance, robustness and maintainability. It is
myopic to assume that there is only one way to do something and naive
to think that that one way will occur to everyone who approaches the
problem independently.

If collections are re-fetched every time they are used, the speed of a
loop using a live collection should be very much slower than one using
a static collection. In IE, working with collections generated by
getElementsByTagName is very much faster than using HTML DOM
collections like table.rows (both collections are live). That
provides a hint to me that one has been implemented efficiently, the
other hasn't. If all such collections were simply re-fetched every
time (or implemented using the same basic logic, whatever that might
be), the speed difference would not be so pronounced. So there are
likely at least two different approaches implemented in IE, and any
claims that there is only one way to do it need more proof than simple
conjecture.

The fact that browsers have been dealing with live collections for
over a decade and that some perform very much faster than others
indicates to me that they likely use highly optimised algorithms that
do not simply re-get entire collections every time they are required.

A live collection is no more than a static list whose getters do a
refresh, an update, a re-build.

Unless you *know* that to be the case (and I don't think you do), you
can't claim that is how it has been implemented as a general solution
in modern browsers. In any case, it is irrelevant how the browser
does it - at the end of the day the question is whether working with
live or static lists with javascript in a particular case is
preferable based on some objective criteria (performance, robustness,
maintainability, complexity, etc.).

Conceded that there's no need to refresh
it unless the "dirty bit" is set in the DOM tree. But a similar strategy
can be applied to static lists as well.

Your argument is based on the supposed performance issue of re-
fetching a live collection whenever it is used. Now you're saying
browsers don't do it because it's inefficient, so there may not be any
performance issue at all (and that view was supported by someone on
the Firefox development team).

[...]
Both take as long to build the first time a certain query is made,

That statement directly contradicts the evidence above and your own
argument. If a static list is a live list converted to static (which
is how Firefox developers plan to implement at least some parts of
qSA), you are assuming the conversion takes zero time. Maxwell's
demon lives! :)
and
subsequent updates can be optimized equally in both cases.


So there is no inherent performance issue. Whether live or static
lists are "better" in a particular case should be discussed in terms
of specific specific requirements related to javascript and the
general statement that live lists are slower or harder to work with is
debunked.

QED.
 
J

Jorge

The point is that if the choice is only one or the other,

A live collection can *not* be emulated in JS.
I'd prefer
to have live lists and convert them to static using JS than having
static lists that I have to update every time I use them to imitate
live lists.




So you haven't.


Unless you provide new information, the I'll reach the same conclusion
(to do otherwise would be illogical). There are dozens of ways to
implement particular functions, 5 or 10 will be equivalent for
criteria such as performance, robustness and maintainability. It is
myopic to assume that there is only one way to do something and naive
to think that that one way will occur to everyone who approaches the
problem independently.

(1) There are only 2 possibilities:

Upon entering the getter, you either

-are confident that the collection is already updated (in that case,
every DOM touch operation must update all the live collections ~=
nonsense),
or,
-it needs to check first wether an update is required, and update or
not, accordingly.
If collections are re-fetched every time they are used, the speed of a
loop using a live collection should be very much slower than one using
a static collection.

And they always are, much more so if/when the DOM is dirty.
In IE, working with collections generated by
getElementsByTagName is very much faster than using HTML DOM
collections like table.rows (both collections are live). That
provides a hint to me that one has been implemented efficiently, the
other hasn't. If all such collections were simply re-fetched every
time (or implemented using the same basic logic, whatever that might
be), the speed difference would not be so pronounced. So there are
likely at least two different approaches implemented in IE, and any
claims that there is only one way to do it need more proof than simple
conjecture.

I'm not saying there's just one way of doing it.
The fact that browsers have been dealing with live collections for
over a decade and that some perform very much faster than others
indicates to me that they likely use highly optimised algorithms that
do not simply re-get entire collections every time they are required.



Unless you *know* that to be the case (and I don't think you do), you
can't claim that is how it has been implemented as a general solution
in modern browsers.

I don't (you neither) need to see the source code: just think: (1)
In any case, it is irrelevant how the browser
does it - at the end of the day the question is whether working with
live or static lists with javascript in a particular case is
preferable based on some objective criteria (performance, robustness,
maintainability, complexity, etc.).
(...)
Your argument is based on the supposed performance issue of re-
fetching a live collection whenever it is used. Now you're saying
browsers don't do it because it's inefficient, so there may not be any
performance issue at all (and that view was supported by someone on
the Firefox development team).
(...)
That statement directly contradicts the evidence above and your own
argument. If a static list is a live list converted to static (which
is how Firefox developers plan to implement at least some parts of
qSA), you are assuming the conversion takes zero time. Maxwell's
demon lives! :)
(...)
So there is no inherent performance issue. Whether live or static
lists are "better" in a particular case should be discussed in terms
of specific specific requirements related to javascript and the
general statement that live lists are slower or harder to work with is
debunked.

QED.

See for yourself:

http://jorgechamorro.com/cljs/058/

qSA is available in Safari 3 and 4, Chrome, FF3.5b, Opera 10 and IE8,
AFAIK.

When dirty DOM: ON, the DOM is touched to be sure that it's dirty.

And let me know,
TIA,
 
J

Jorge

(1) There are only 2 possibilities:

Upon entering the getter, you either

-are confident that the collection is already updated (in that case,
every DOM touch operation must update all the live collections ~=
nonsense),
or,
-it needs to check first wether an update is required, and update or
not, accordingly.

or,
-Blindly update it ever, just in case. (~= lazy)
 
R

RobG

A live collection can *not* be emulated in JS.

We're talking about *browser* methods, and whether the specification
should or shouldn't support live collections. I've already said that
it would be great if it allowed both live and static. The reason I
would like live collections is that for those cases where a static
collection is indicated, it is much simpler in JS to convert a live
collection to static than vice versa (e.g. you have to re-fetch the
static collection each time or update it some other way).

In any case, live collections can be emulated in JS, e.g. you can
provide a DOM manipulation API and specify that collections are only
live if the API is used. You don't have to emulate all the features
of general DOM manipulation API, just the bits required for the job.

At the risk of repeating myself...
I'd prefer
to have live lists and convert them to static using JS than having
static lists that I have to update every time I use them to imitate
live lists. [...]
Unless you provide new information, the I'll reach the same conclusion
(to do otherwise would be illogical).  There are dozens of ways to
implement particular functions, 5 or 10 will be equivalent for
criteria such as performance, robustness and maintainability.  It is
myopic to assume that there is only one way to do something and naive
to think that that one way will occur to everyone who approaches the
problem independently.

(1) There are only 2 possibilities:

Upon entering the getter, you either

-are confident that the collection is already updated (in that case,
every DOM touch operation must update all the live collections ~=
nonsense),

Not at all. Another method is to keep references to the collections
that an element belongs to so that when the element is modified so is
the collection. Another is to create an index system for the most
common collections, there are likely others.
or,
-it needs to check first wether an update is required, and update or
not, accordingly.


And they always are, much more so if/when the DOM is dirty.

I guess you are basing that on your tests, see comments below.

[...]
See for yourself:

http://jorgechamorro.com/cljs/058/

qSA is available in Safari 3 and 4, Chrome, FF3.5b, Opera 10 and IE8,
AFAIK.

When dirty DOM: ON, the DOM is touched to be sure that it's dirty.

And let me know,

The flaws I see in the test are:

1. It doesn't update the static collection when the DOM is dirty -
clearly that needs to be done if the static collection is to provide
the same functionality as a live one

2. It doesn't test scenarios of looping over a collection when some
part of the DOM that doesn't belong to the collection is modified

3. It gets the length of collections every time - that may be
irrelevant, but it might not either.

I ran the script in Safari 4 on a 1GHz G4 MacBook, Firefox 3 died. The
results were:

Method Dirty not Dirty
(ms) (ms)
live 350 2.61
static 118 0.35
qSA 122 2.49

Summary: static was about 3 times faster than live for dirty, 8 times
faster for clean. qSA is the same speed as static for dirty, but the
same speed as live for clean (dunno what to make of that).

What do I get from the above?

1. Live collections are updated whenever elements in the collection
are modified (as expected). It doesn't show whether it is updated:

a. unconditionally whenever the DOM is modified,
b. only when a member of the collection is modified,
c. only when the collection is accessed, or
d. some other epoch

can't be determined from this test (the suggested non-collection DOM
modification will help clear that up). The test also doesn't reveal
how the collection is updated (is it re-fetched or a more
sophisticated algorithm used).

2. The comparison between qSA and static shows probably nothing
special happens when a static collection is accessed (as expected)

3. Accessing the members of an array by index is faster than accessing
the members of a live collection by index. Why that occurs can't be
determined by the test, it may have nothing to do with the nature of
the collection and more to do with the fact that arrays might be more
highly optimsed for such access. There is no reason why accessing the
collection is slower when the DOM hasn't been modified.

4. Whether a live or static collection is more efficient can only be
determined on a case by case basis.

If the DOM methods don't provide live collections, that's one option
that isn't available. Implementing live collections from static in JS
is likely much more expensive than implementing static from live.
However, the best solution would be for both to be available so
programers have a wider range of tools at their disposal.
 
J

Jorge

Yep, it will most definitely be inefficient, error-prone and limited by
a tiny subset of browsers, but it is possible :)

I just wrote a simple implementation as a silly but fun exercise (tested
in FF3.0.10, but should work in any client that supports mutation
events, i.e. "DOMSubtreeModified"):

Both of you're cheating... :) I said emulate a live collection, say
dGEBTN, i.e. with the same "API". You can't do that without getters,
AFAICS. So, nowadays, not cross-browser. Am I wrong ?

e.g., fetching collection.length might need to trigger a refresh .
e.g., fetching collection[n] might need to trigger a refresh.

Also, you can't depend on events to refresh it: if you do, it won't be
refreshed untill the next event dispatch cycle... or IOW, too late to
be a valid solution to the problem. Or not ?

Nice try, anyways !
 
J

Jorge

Jorge wrote:
(...)

Interesting. I didn't think about it.

Well, forget it because those mutation events get executed
instantaneously !
Those are really mutation "interrupts"... :

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">

<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Interrupts or events ?</title>
<!-- Date: 2009-06-11 -->
<script type="text/javascript">
window.onload= function () {
var ctr= 0;

var getLive = (function () {
var collections = {};
var _slice = Array.prototype.slice;

window.addEventListener('DOMSubtreeModified', function () {
ctr++;
for (var prop in collections) {
// keep same array object, but clear it
collections[prop].length = 0;
var temp = getByTagName(prop);
// overwrite
for (var i=temp.length; i--; ) {
collections[prop] = temp;
}
temp = null;
}
}, false);

function getByTagName(tagName){
// replace with qSA
var collection = document.getElementsByTagName(tagName);
return _slice.call(collection, 0);
}

return function(tagName) {
// memoize
return collections[tagName] ||
(collections[tagName] = getByTagName(tagName));
}
})();

var div, divs = getLive('div');
var after, before= divs.length; // 5
alert( divs[0].parentNode.removeChild(divs[0]).innerHTML+ "["+
ctr+ "] "+
divs[0].parentNode.removeChild(divs[0]).innerHTML+ "["+ ctr+ "]
"+
divs[0].parentNode.removeChild(divs[0]).innerHTML+ "["+ ctr+ "]
"+
divs[0].parentNode.removeChild(divs[0]).innerHTML+ "["+ ctr+ "]
"+
divs[0].parentNode.removeChild(divs[0]).innerHTML+ "["+ ctr+ "]
"+
" divs.length: "+ divs.length); // 0 !
};
</script>
</head>
<body>
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
</body>
</html>

Yields: 1[1] 2[2] 3[3] 4[4] 5[5] divs.length: 0

!!!
 
V

VK

Sorry for jumping into your discussion, but I am really curious what
is this discussion about? NodeList and legacy HTMLCollection are both
dynamic ("live"). So why anyone needs such a twisted around code for
something that already done on system level?
 
J

Jorge

Sorry for jumping into your discussion, but I am really curious what
is this discussion about? NodeList and legacy HTMLCollection are both
dynamic ("live"). So why anyone needs such a twisted around code for
something that already done on system level?

querySelectorAll isn't a live collection: that's what started the
debate.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top