Closed Bug 620852 Opened 14 years ago Closed 14 years ago

Inconsistency between script's async attribute and property

Categories

(Core :: DOM: Core & HTML, defect)

defect
Not set
normal

Tracking

()

VERIFIED INVALID

People

(Reporter: mozilla, Unassigned)

References

()

Details

User-Agent:       Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)
Build Identifier: 4.0b9pre (2010-12-21)

Investigation and further testing lead me to believe an oversight was made in the fixing of #602838 (which originally came from breakage caused by #591981), which creates an inconsistency between how a parser-inserted script element's `async` attribute works and how a script-inserted script elements `async` (reflective) property works.

This blog post comment I made explains the situation in detail:

http://www.nczonline.net/blog/2010/12/21/thoughts-on-script-loaders/#comment-9108

In a nutshell, the script-inserted script element's `async` property works as a true/false boolean value. But the parser-inserted script element's `async` attribute works as a (now) confusingly different "boolean" attribute (aka, present/not-present).

For instance, I would assume (reading the wording of my proposal that prompted #602838) that if I had a markup script tag and I set async="false", that it would behave the same as:

1. async=false on a script-inserted script element; AND
2. no `async` attribute at all on the parser-inserted script element

However, saying async="false" in markup still results in async being turned on for that script element.

I would thus suggest a slight modification to the behavior of a parser-inserted script element's `async` property value interpretation:

1. If the value is exactly "false" (or any capitalization thereof), the script element should behave EXACTLY the same as if `async` property wasn't specified at all.

2. If the value is anything other than "false" (including no value at all, or "true", or "async", or "foobar"...), the async attribute is turned on.

This minor change will bring the `async` attribute's semantics more into line with the reflective `async` property's semantics.

---------
I always intended for my proposal to create symmetry and consistency between the attribute and property values and behavior. It was an oversight on my part that my original proposal left this detail out. I would ask that Mozilla consider this additional change, to close up the inconsistency gap.

I can't imagine that there's any existing web content that is actually setting `async="false"` on markup script tags and still expecting that to turn async on, so I don't believe my request here will create backwards compatibility issues.

Reproducible: Always
Depends on: 602838
Doh! I wish I could edit that original description. I said "property" in several confusing places when I meant "attribute". Let me re-do:


...
I would thus suggest a slight modification to the behavior of a parser-inserted script element's `async` attribute value interpretation:

1. If the value is exactly "false" (or any capitalization thereof), the script element should behave EXACTLY the same as if `async` attribute wasn't specified at all.

2. If the value is anything other than "false" (including no value at all, or "true", or "async", or "foobar"...), the async attribute is turned on.
...
> However, saying async="false" in markup still results in async being turned on
> for that script element.

Yes.  If the async content attribute is set, the script is async.  It doesn't matter what value it's set to.  That's how boolean attributes behave in HTML: what matters is whether they're set or not.  Boolean attributes that are reflected into the DOM will add the attribute when the DOM property is set to true and remove the attribute when it's set to false.

None of this has anything to do with bug 602838.

> I can't imagine that there's any existing web content that is actually
> setting `async="false"` on markup script tags and still expecting that to
> turn async on

It doesn't matter what it _expects_.  If web content does that right now, it gets async behavior.  That's what the HTML5 spec calls for.  And that's what we implement.  Changing it at this point would in fact break compat in a way we don't want to break it.  It would also make this one attribute behave differently from every single other boolean attribute in HTML, which doesn't seem at all desirable.
Status: UNCONFIRMED → RESOLVED
Closed: 14 years ago
Resolution: --- → INVALID
Status: RESOLVED → VERIFIED
I am *specifically* asking for a small exception to how the "boolean" attribute works in this case. I (now) understand how it currently works, but I think it would be more sensible to make this one small exception.

The very small limited exception is ONLY this:

The exact value "false" (and only that value) will negate the setting of the attribute. Otherwise, everything stays exactly the same. 

As part of my ongoing effort to update the spec regarding script and async, this exception is also something I'll be asking for.

I think the positive benefit of the async attribute and property working semantically the same (reducing confusion, like Nicholas asserted in that blog post) is GREATER than the diverging in a slight way from the way the spec currently reads.

Mozilla already stepped outside the spec to implement bug 602838, ostensibly as forward-thinking that such proposal may have a decent chance to make into the spec eventually.

The reason *this* additional exception request is related is because my original intent with that proposal that led to bug 602838 was to ask for coherent consistency between the attribute and the property. Had I understood then what I understand now, I would have been asking for this small exception from the beginning of the discussions.

As for feasibility of the change:
This can't be much more complicated than a simple if-statement in the algorithm at the point where it's flagging a script element with "async" or not, right? If it sees async but the value is "false", just ignore it.

I really don't understand how this would break compat, because as I said, I'm almost positive there's nowhere that anyone is doing something as silly as `async="false"`. In fact, I bet we could devise a simple markup page crawler for the 500,000 top ALEXA pages and still not find a single occurence of it.

As I recall from the W3C discussions on the bug 602838, a major concern was not just the sensibility of what I was asking for, but also whether or not it would create backwards-compat issues with existing content. I don't think any reasonable case could be made that the exception I'm asking for would break existing content.

Even if there *WAS* one stray site out there which did async="false" in the markup, the "breakage" wouldn't be functional, only lower performance (but probably not even by a lot). And performance is a pretty small surface area of "breakage" to educate sites on the change. Those sites are certainly already tolerant of the lowered performance in cases where browsers don't support "async" at all, like all the IE's (even IE9), etc.

It's important to understand, I'm not at all suggesting that any site SHOULD do async="false". What I'm suggesting is, the ability to do that (and have it work the same as setting the property to false for a dynamic script element) makes the documentation and education about `async` more coherent and consistent.
Kyle, adding that exception significantly complicates both the conceptual model (for example, introduces meaningful case-differentiation for built-in values in HTML, which doesn't exist right now!) and implementation.  Again, the benefits of working _exactly_ like every single other boolean attribute works instead of creating weird special cases shouldn't be thrown away lightly.
To be clear, you want consistency between values of a boolean attribute (which are currently meaningless, btw; the only values the spec allows are async="" and async="async"; anything else is not valid HTML) and boolean values in javascript.  But this "consistency" is not present anywhere else in HTML, so I'm not sure why it would be particularly desired here.
@Boris-
Yes, it's a fair point that there are plenty of other places where the semantics of true/false in JS don't map to the semantics of present/not-present in markup.

In all truth, I think this is a mistake in HTML, and such attributes *should* have the special behavior of looking for "false" as the value and thus ignoring the attribute.

For instance, things like   

<button disabled="false" />
<button disabled="true" />

would, in my opinion, make a lot more sense in markup than:

<button />
<button disabled />

So, it's a fair point that I actually think this change should be made for all "boolean" attributes. I'm pretty sure that I'll never get any cross-browser support for that. It's just me, I guess.

BUT--
This particularly confusing semantics around this new behavior for `async` DOES make the problem worse. A criticism of my proposal for `async=false`, which is valid, is that I've created basically a three-state situation, where the value is either true, false, or not-present. 

Well, not in reality, but it APPEARS that way from the casual glance, which now makes `async`s full behavior harder to explain to people. Nicholas Zakas, on that blog post, is a clear example of someone who's really skilled in HTML/JS and *still* gets it wrong after several attempts. I think *perhaps* if this `aysnc` attribute's semantics matched its reflective property's semantics, the confusion would be/have been less.

-------

All this is to say, deep-down inside, I know that I'll never get all boolean attributes to behave like I think they should. That ship sailed long before I even got into web dev. BUT, I do perhaps have a little influence on `async` here.

So, rather than necessarily fight the losing battle of changing all "boolean attributes" semantics, I would suggest that `async` as an attribute should NOT be a "boolean attribute" as the spec has defined. I think it should be a different kind of attribute, one whose value is semantic. There's lots of other examples of attributes in HTML whose value has semantic meaning, including `rel`.

The path to change `async` to a different kind of attribute wouldn't have to create backwards-compat issues, because the way I'm suggesting the semantics, it'd be that "false" is the only special value, and any other value (including "true", "async", or no value at all) would be taken as the truthy/present case.

The only possible breakage in that respect would be any sites which are doing async="false" in their markup and are instead still relying on async being truthy. If there's anyone silly enough to be doing that, I'd be shocked. That number has to be 0 or so low that re-education and fixing those few sites wouldn't be a significant problem.

In the end, if you don't want to change `async` to something different than a strict "boolean attribute", I understand. But I really do genuinely believe the semantics of how I'm suggesting that attribute SHOULD work are better and less confusing.

And, if it turned out to be a success, it could be a proving ground for making the exact same type of change to all boolean attributes someday. Again, I can't imagine there's any or many sites out there that are intentionally doing `disabled="false"` but who actually want/accept that it's currently doing the opposite. It can't get much more unsemantic than to be completely polar opposite.
@Boris-

> for example, introduces meaningful case-differentiation for built-in values in
HTML, which doesn't exist right now!

I said in my original statement above that "false" as a value should be case-insensitive. As far as I know, this is already precedent on things like `rel`, where "Stylesheet" is the same meaning as "stylesheet", right? 

If that's the case, I'd suggest that "False", "false" and "FALSE" are all the same value as far as the semantics I'm suggesting.

And if it's not the case, and currently "Stylesheet" *is* different that "stylesheet", then that same pattern could also be copied to what I'm suggesting, and thus the only falsey value recognized would be strictly "false".

In either case, I'm not suggesting a precedent (as far as casing goes) that's not already in lots of other attributes.
> I said in my original statement above that "false" as a value should be
> case-insensitive.

Ah, I must have misread that.  But then why is " false" not a false value?

Seriously, you don't want to mess with HTML boolean attributes.  They're complicated enough as it is.
> But then why is " false" not a false value?

I dunno. If " stylesheet   " works for `rel` then " false" should work. If not, then no. I'm suggesting an extremely limited exception that fits with normal semantics, not trying to create a whole range of possible falsey value string representations. 

I'm trying to suggest that as much as possible, the "rules" for how the value would be interpreted are borrowed from precedent in other attribute types, like `rel` for instance.

> Seriously, you don't want to mess with HTML boolean attributes.  They're
> complicated enough as it is.

OK, fine, I get they're complicated. I get that my chance of ever changing them is practically zero. A boy can still dream, though, right?

I still don't understand why `async` has to be a "boolean attribute". Why can't it be a normal attribute? Why can't it be entirely different and seperate from the "boolean attribute" baggage, and just be a value whose simple semantics are: "false" means "ignore me", and any other string means "set me"?

I think this new type of atrribute, call it "uber-boolean" if you want, has merit, independent of `async`. I think it makes more sense. And maybe, someday, in HTML9, someone might thing "you know, all the places where we say attributes are 'boolean', let's change them all to say they're 'uber-boolean'".

But the biggest place where this new "uber-boolean" would help *right now* is because of the complexity that now exists around `async`. The fact is, "async" itself is a terrible name for this behavior. But because it's a bad name that we're stuck with, it needs extra help to make sense, at this point.
@rel is a space-separated set of tokens.  So rel="this is a stylesheet" will work to load a stylesheet, say.

> I'm suggesting an extremely limited exception that fits with normal semantics,

No.  You're suggesting an exception that precisely does NOT fit with normal HTML semantics.
@Boris-

I mean, we can split hairs all we want on what is "normal semantics" and what isn't. I'm suggesting a VERY limited exception that says that "false" and only "false" be taken as a special value. In the case of `rel` values, sure, multiple values make sense. In the case of `disabled`, `async`, and many other "boolean attributes", ONLY something like "false" would make sense. 

We could very easily narrow it all the way down to only "false" and not " false" or "FalsE" or any variations, and it'd still make perfect semantic sense to me.

Basically, if I want to define a semantic value for an attribute that means the same as not putting the attribute in there at all, "false" seems like the only reasonable candidate. Any other variation would likely just be nonsense noise used to strawman argue or bikeshed my suggestion to death.
My point is that we don't want @async to behave differently from other boolean attributes.  And changing _all_ boolean attributes to treat some value as not being set is very likely to cause compat issues.  So we have no plans to do that.  But you're welcome to try to convince the spec editor, with data to back it up, that there's no compat issue and the change is beneficial.
@Boris-

OK, this is a fair enough stance. I didn't frankly expect this exception to get accepted just for `async`. But I wanted to try, because I think there's a better chance of getting such a change spec-wide if it's already been proven to work and be feasable for one such attribute. And given the flux of the `async`, and it's additional semantic challenges, it seemed like a decent enough reason to try, and right during that flux.

I *am* curious though, if Mozilla *were* to just make the change (and only the narrow change, nothing else) I'm suggesting, either only for `async` or even for ALL boolean attributes, what "compat issues" do you think are "very likely"?

I'm really confused by that assertion, because I think I've specified my suggestion intentionally in such a way as to severerly minimize or completely eliminate compat issues.

Do you know of, or have you ever even heard rumor of, any site, anywhere, that was using some boolean attribute, and was specifying it in markup like `disabled="false"`? 

I would love to see even one example of a site doing that. Because the obvious and important question for such a site is: 

Why are you doing something whose semantics (ie, that you clearly are saying you want the attribute turned off) and its actual behavior (all boolean attributes specified like this are in fact still considered on) are completely opposite? Is there some use-case for this strangely opposite/confusing semantics that I'm missing?

My hunch is, we couldn't find a site doing this (intentionally) if we tried. And if we did, and they were intentionally doing it, I bet upon even slight investigation, we'd help them see the mismatch of their semantic intent and the actual outcome, and it'd be an easy re-education.
A quick search comes up with http://www.google.com/codesearch/p?hl=en#qMFY3IOEKqo/trunk/qooxdoo-0.8.1-sdk/framework/source/class/qx/test/bom/Basic.js&q=disabled%3D%22false%22%20lang:javascript&sa=N&cd=20&ct=rc where it appears qooxdoo is relying on `disabled=false` actually being disabled (see corresponding this.assertEquals(true, attrib.get(document.getElementById("test5"), "readonly")); test)

If the behavior of disabled=false were changed, wouldn't this test fail?
(In reply to comment #14)

> (see corresponding this.assertEquals(true,
> attrib.get(document.getElementById("test5"), "readonly")); test)

Forgive the copypasta mistake, that should be: this.assertEquals(true, attrib.get(document.getElementById("test5"), "disabled"));
So, if I interpret that code correctly (and I guess I need to check with qooxdoo's author to verify), it would appear they are doing a feature-test for "disabled" by seeing if setting 'disabled="false"' actually still gets set to `true` in the reflected property? Does that sound right?

This is a bizarre backwards set of code, but it seems obviously like a valid example that would break in my suggestion. However, it would seem like the feature-test would be just as valid as if had said 'disabled="foo"', right?

Unless I'm missing something (and the setting of "false" is revealing something important that "foo" would not), I'd argue this is one of those cases where re-education to not do something that's semantically opposite of its intended behavior would be in order.

Moreover, I bet cases where people are doing this are pretty limited, to a few frameworks and test harnesses, rather than out-in-the-wild markup web content.
> if Mozilla *were* to just make the change (and only the narrow change, nothing
> else) I'm suggesting

I'm not sure why we're assuming this counterfactual.  We don't want to make such a change that would make one boolean attribute different from all others.

> what "compat issues" do you think are "very likely"?

If we just change @async, they aren't; to a first approximation that attribute is not used on the web.  My "very likely" comment was about changing the behavior of all boolean attributes.

> Do you know of, or have you ever even heard rumor of, any site, anywhere,

See above.

> Because the obvious and important question for such a site is: 

It doesn't matter what the site is "thinking" or what the "semantics" are.  The point is that this would be a browser behavior change that would break sites, for no good reason.  We won't do that, and neither will any other browser.  The benefit being zero means that any cost is not acceptable.  Now can we drop this line of discussion, please?  This change is not happening, period.
>  Now can we drop this line of discussion, please?  This change is not 
> happening, period.

Well, good grief, that's not very friendly or helpful to just tell me to shut up. I was just trying to have a productive discussion/debate about the topic so I could understand the opposition better. Sorry to be wasting your time. Feel free to remove yourself from the "CC" list at any time. Sheesh.

> We don't want to make such a change that would make one boolean attribute 
> different from all others.

Fine. I already conceeded that point in the previous message. I'm now only trying to examine why such a change would be so disastrously awful for all boolean attributes. You know, in case I go to the spec group with this idea, I was just trying to see if there was any land-mines I might not yet be aware of.

Thus far, there's a bunch of handwaving about "that's how the spec says it" and "that might break a bunch of sites", but I don't see much hard reasoning as to REALLY why.

> The point is that this would be a browser behavior change that would break 
> sites, for no good reason.  We won't do that, and neither will any other 
> browser.

Bogus. Browsers make changes all the time that break existing content. You almost cannot make a change without breaking *someone's* content. 

Heck, the whole reason I got into this fray is because Mozilla broke *my content*.

And if you're just gonna say "well, the spec told us to" I also call bogus, because (from an outsider's point of view, like mine), it's impossible to decipher issuer-per-issue if a change should be first advocated to spec, then the browsers, or if it should first be advocated to be implemented experimentally in a browser and the spec will later agree.

In either case, it should be tolerable by both the spec group and browser developers to discuss and explain why something has to be a certain way, not just dismiss the idea with generalities, assumptions, and abstract assertions.

There usually seems to be a measured discussion about pros and cons, about the widespread nature of a proposed change, how much of an issue that compat breakage would be, if it is something that's breaking but should be re-educated, if there are workarounds, etc. In all of those discussions, people *reason* about what sites intend, what the spec intends (and says), what browsers want/intend, etc. 

It's an entirely fluid and complex process. And yet you're now trying to make it a simple binary one just to get me to shut up.

Moreover, there's yet to be any showing of any substantial amount of sites or code that would break. We have one example thus far. Does anyone even know how many sites that's used on?

> The benefit being zero 

It's not a huge semantic benefit, I'll admit that. It's pretty tiny in the overall scheme of things. But it's not zero. It's zero to *you* maybe, but it's not zero to everyone. It would definitely help my case/explanation/evangelism for "async=false", no question about that.

> means that any cost is not acceptable.

Any cost? You mean the development cost to add it to the browser? Or the cost to the (unknown but probably really small) amount of web content it might break?

I can't speak to the development cost to such a change for all boolean attributes. But it would conceptually seem like a pretty small change, like a single if-statement that ignores any boolean attribute if its value is "false". Maybe it's actually a huge code change. I dunno.

I was really just trying to examine just how likely it is that there's a substantial amount of existing content such a change would affect. I was also trying to examine if in any of those rare cases, a simple workaround wasn't reasonable and even obvious/desirable (aka, don't use "false" when you really mean "true").
> Bogus. Browsers make changes all the time that break existing content.

The key part is "for no good reason".  That part is _very_ important in a cost-benefit analysis.  No benefit, nonzero cost == don't do it.

It really sounds like we're coming at this from different presuppositions about the benefits of this change; given that, I don't think we're going to come to an agreement....
> It really sounds like we're coming at this from different presuppositions 
> about the benefits of this change; given that, I don't think we're going to 
> come to an agreement....

We clearly are coming at it from different positions. That's a good thing, though. It doesn't mean discussion should never happen if people can't agree. In fact, discussion where people disagree (in a healthy and respectful manner) is usually how progress eventually happens.

> The key part is "for no good reason".  That part is _very_ important in a
> cost-benefit analysis.  No benefit, nonzero cost == don't do it.

You're saying the benefit is zero, I'm saying it's really small, almost inconsequential. But the benefit being small (or zero) has never been my whole point throughout this entire thread. The *COST* is what I've been trying to examine.

If the benefit is 0.1, but the cost is 0.99999999, they're both pretty small (and probably a waste of your time to consider). But that doesn't always mean it's an idea that should be summarily dismissed as irrelevant to even explore.

Has Mozilla ever made a change to the browser that isn't in the spec (or even made a willful violation or reinterpretation of spec) to appease a particular sub-section of the web audience? I know they have.

Has Mozilla ever made a change to the browser that broke some obscure site/code that had some seemingly illogical (and thus, not considered at time of change) usage of some part of HTML? Of course.

All I'm saying is, I don't think it's particularly heretical to *consider* another such a change's pros and cons. 

But, apparently "boolean attributes" are just so baggage-laden or set in stone that noone wants to ever think about them again.
Component: DOM → DOM: Core & HTML
You need to log in before you can comment on or make changes to this bug.