Support from Acquia helps fund testing for Drupal Acquia logo

Comments

RobLoach’s picture

Status: Active » Needs review
FileSize
397 bytes

What if we just don't babysit broken code that doesn't work asynchronously?

mfer’s picture

In several browsers the default case is true already. Sure, we can set it to true explicitly. I was more looking for a way to set it to false. Like if I have a script that decides to do a document.write().

Note: you really should never have a script do a document.write(). Really, if you are considering it... don't.

RobLoach’s picture

Status: Needs review » Needs work

I guess in some cases, you would want async to be false. With tracking scripts, like Chartbeat, where it times how long the page takes to load, you'd want the script to load inline. So, TRUE by default, but allow setting to FALSE?

mfer’s picture

async = true is a contract with the browser not to use document.write(). If you are going to use document.write() (a terrible idea but a freedom I don't want to take away from people) you need to set async to false.

Jacine’s picture

bleen’s picture

Given http://groups.drupal.org/node/210973, I think this can/should be backported

cosmicdreams’s picture

so it kind of sounds like a good solution for this is to add an argument to the drupal_add_js to govern whether it should be asyc or not and default that argument to true.

Does that sound like a good plan?

bleen’s picture

re #7: sounds like a plan

medden’s picture

Chris Coyier has written a great article on why Async is the way to go...

http://css-tricks.com/thinking-async/

cosmicdreams’s picture

I tried to created the patch I described in #7 but it quickly became complex. I'll try again next week.

nod_’s picture

Bevan’s picture

The HTML5 async feature does not yet have very wide browser support. On the other hand, loading scripts last is a well-tested, simple and commonly used technique that does not require any special browser support: #784626: Default all JS to the footer, allow asset libraries to force their JS to the header

nod_’s picture

Status: Needs work » Postponed

I agree that this one should be postponed until browser support is sufficient in the latest stable versions of the main browsers (IE/FF/Chrome/safari/Opera).

Unless comicdreams or someone else can make a patch which shows it doesn't impact negatively browsers not supporting it while still working properly if the browser supports it I'm postponing this one.

bleen’s picture

Status: Postponed » Active

According to my testing using this test: http://test.getify.com/test-async/ there is support for async in all major browsers (except IE which I didnt have available): FF 7+, Chrome12+, Safari 5+, Opera11+

Further, there has never been (to my knowledge) a case where including an unsupported attribute has a negative effect on older browsers. They are simply ignored. As evidence (non-conclusive) of this, note that Google has implemented async for all its analytics and advertising (Doubleclick) products:
http://googlecode.blogspot.com/2009/12/google-analytics-launches-asynchr...
http://support.google.com/dfp_premium/bin/answer.py?hl=en&answer=1638622
I dont think Google would be suggesting that publishers include this on their ad tags if it had a detrimental effect on older browsers given the blowback they would get from their high-paying customers in this realm.

One more post on this (as of 7/11):
http://stackoverflow.com/questions/1834077/which-browsers-support-script...

nod_’s picture

Status: Active » Needs work

Well this attribute is not like any other HTML attribute. Async, ok but does it preserve the order? If all the major browsers don't give the same answer or have half-working implementations we won't be able to put that in core.

The first link is not working for me in Opera 11.61 or 12. Google is different, they have only 1 script to load not the 20+ we usually see on Drupal websites.

Again, talking about this is not very useful unless we have a patch to review and see what's going on for Drupal. #1 looks good but needs a reroll.

bleen’s picture

Google is different, they have only 1 script to load not the 20+ we usually see on Drupal websites

This issue is simply about adding support for async, not about implementing it for all the js files included on a Drupal site. I dont think you can consider the async property for any js file where order is important. But this would be very helpful for any site that uses the DART module, or the GoogleAnalytics module, or [insert third-party integration module that includes a js file here]

iamEAP’s picture

bleen18 is correct. Async does not preserve order; if that's the desired behavior, you use defer, which is already supported by Core.

If Drupal 8 is to be HTML5 ready out of the box (as I've been hearing), the async attribute should have support in drupal_add_js, as it's in the current draft HTML5 spec.

I think the agreement is to default to FALSE (current behavior), and allow the user to set TRUE.

Implementation would be almost identical to how the defer attribute is set. I bet a significant amount of existing code could be borrowed to achieve this.

iamEAP’s picture

Status: Needs work » Needs review
FileSize
1.81 KB

Here's a preliminary patch that adds the async attribute. As per the spec, it only adds it to script tags that contain an "src" attribute.

What I'm not sure of his how to handle aggregation of async/defer scripts. Maybe it's a separate issue; I'm not sure how core handles defer scripts and aggregation.

(While patching, I found that defer is implemented incorrectly. Separate issue created here: #1503804: Defer attribute should not be added to inline scripts or settings.)

arnested’s picture

I agree with iamEAP (#17) that async should default to FALSE and that you should be allowed to set it to TRUE.

His patch in #18 looks sound and works fine although I would add the code regarding the async attribute next to the code about the defer attribute, see attached patch.

iamEAP’s picture

Agree with arnested in #19.

Echoing comments from nod_ in the aforementioned defer bug thread, here's a patch that cuts down on some of the redundancy.

I'm also attaching a second patch that takes care of both this and the defer bug in a nice, neat way.

arnested’s picture

Status: Needs review » Reviewed & tested by the community

Yes, much better approach in #20.

Reviewed and tested. Works like a charm.

bleen’s picture

Status: Reviewed & tested by the community » Needs review

Please be specific about which patch in #20 you are RTBCing

arnested’s picture

Status: Needs review » Reviewed & tested by the community

Please be specific about which patch in #20 you are RTBCing

Sorry. I reviewed and testet both patches.

I prefer the second patch though since it incorporates the patch from #1503804.

iamEAP’s picture

Status: Reviewed & tested by the community » Needs review
FileSize
1.99 KB

This patch landed: #1503804: Defer attribute should not be added to inline scripts or settings, which makes our patching lives a little easier. Here's a re-roll of #20 (the second one).

Could use a couple more opinions in addition to arnested, since this is an API addition.

bleen’s picture

Status: Needs review » Reviewed & tested by the community

I think #24 is ready to go.

catch’s picture

Status: Reviewed & tested by the community » Needs work

What I'm not sure of his how to handle aggregation of async/defer scripts. Maybe it's a separate issue; I'm not sure how core handles defer scripts and aggregation.

I don't think this is a separate issue, although we may have a pre-existing bug if defer isn't handled already in the aggregation logic. Would be good to at least check what the current situation is and open a related bug report before commit, or add support here.

iamEAP’s picture

A quick look at drupal_group_js() shows defer is not currently handled in any special way: a pre-existing bug.

I created a new bug report that takes both async and defer into consideration. See: #1587536: JavaScript aggregation should account for "async" and "defer" attributes

With that said, I think it's worth committing this in the meantime. The bundling only affects half of the async functionality anyway, as it can be applied to external JS resources in addition to files.

iamEAP’s picture

Status: Needs work » Reviewed & tested by the community

Throwing this back to RTBC unless there are strong opinions otherwise.

Jacine’s picture

Priority: Normal » Major

Bumping the priority to major as this needs to be resolved for Drupal 8 as part of the HTML5 Initiative.

I don't think this is a separate issue, although we may have a pre-existing bug if defer isn't handled already in the aggregation logic. Would be good to at least check what the current situation is and open a related bug report before commit, or add support here.

catch, is #1587536: JavaScript aggregation should account for "async" and "defer" attributes sufficient or are you looking for that to be solved here?

ericduran’s picture

Status: Reviewed & tested by the community » Needs work
Issue tags: +Needs tests

I also think this is a major, but this should be tested.

I see two test that should be added.
- Text async on external scripts. Should be as simple as testAddExternal
- Test async on internal scripts. Practically the same as the previous test except adding a call to misc/collapse.js or some other internal js file.

ericduran’s picture

Status: Needs work » Needs review
Issue tags: -Needs tests
FileSize
4.21 KB

Test attached. Testing async and defer since we modified them both here.

I'm ok RTBC-ing this. But I'll leave it to someone else. This should be good to go.

iamEAP’s picture

Status: Needs review » Needs work
+  /**
+   * Tests adding external JavaScript Files with the async attribute.
+   */
+  function testDeferAttribute() {

Comment for testDeferAttribute should say "defer" rather than "async."

ericduran’s picture

Status: Needs work » Needs review
FileSize
4.21 KB

I knew a comment would ruin it lol :)

iamEAP’s picture

Status: Needs review » Reviewed & tested by the community

If it works for testbot, it works for me.

sun’s picture

Lovely patch. Would it be wise to conditionally default 'async' to TRUE, if 'external' is TRUE? (not possible for D7, but considerable for D8)

iamEAP’s picture

Hmm...

Suppose someone used Google or another CDN for jQuery. The first time they loaded the page, they might get a slew of JS errors because some jQuery-dependent code would have fired before jQ was loaded, but afterward, because it was in his/her cache, they wouldn't get any errors. They might spend some unneeded time debugging, or looking through the API docs, or not realize there was a problem to begin with.

Or perhaps a third party service that requires the inclusion of multiple external scripts with interdependencies...

This isn't really my area of expertise, though.

catch’s picture

Version: 8.x-dev » 7.x-dev
Status: Reviewed & tested by the community » Patch (to be ported)

I'm OK with the follow-up, just bumped that to major though.

Committed/pushed this one to 8.x, since we'll only hit the bug if using the property, and we already have that with defer.

I don't think the backport should be committed until the other issue is fixed, but that's up to David/webchick.

mfer’s picture

Priority: Major » Normal

@iamEAP The patch defaults async to FALSE. It just provides the option for TRUE. So, Drupal from a CDN by default wouldn't be a problem. Not unless someone deliberately set async to TRUE. This is not something to be worried about.

I wouldn't consider this high priority either. The script tag in Opera and IE9- doesn't support async. If you actually want async across browsers you need to do it by hand. This is just a nice to have for now.

iamEAP’s picture

@mfer My comment was in reference to sun's proposal to change the existing patch to conditionally default async to TRUE; I was just supporting keeping the existing patch in place.

I agree that backporting this is not a major issue; that being said, I think catch meant to mark #1587536: JavaScript aggregation should account for "async" and "defer" attributes as major in #37, but didn't.

arnested’s picture

#38:

I wouldn't consider this high priority either. The script tag in Opera and IE9- doesn't support async. If you actually want async across browsers you need to do it by hand. This is just a nice to have for now.

Sure older browsers don't know how to interpret the async attribute. But by specifying in drupal_add_js() that a JavaScript is supposed to be loaded asynchronously we can have Drupal 8 create clean HTML5 output and let a contrib module pre_render the scripts to output some old-browser-compatible workaround instead.

I created a proof-of-concept module for exactly that: http://drupal.org/sandbox/arnested/1630800.

This approach will also make it a lot easier to change our "old fashion asynchronous script loading technique" down the road.

diggingrelic’s picture

Assigned: Unassigned » diggingrelic
diggingrelic’s picture

Patch for D7 backport.

diggingrelic’s picture

Status: Patch (to be ported) » Needs review
diggingrelic’s picture

Sorry, learning how to do this.

iamEAP’s picture

Status: Needs review » Needs work

Close, diggingrelic. Your patch is missing code from drupal_pre_render_scripts() that actually adds the property to script tags.

Additionally, as catch pointed out in #37, we may want to hold off on the backport until #1587536: JavaScript aggregation should account for "async" and "defer" attributes is resolved, depending on how the D7 maintainers feel. Once that's resolved, we may just roll all of it up into a single patch here.

diggingrelic’s picture

Okay. Thank you for your response.

cweagans’s picture

grendzy’s picture

Version: 7.x-dev » 8.x-dev

With async scripts, the onload attribute is important as well (especially since the developer can't predict when or in what order an async script will execute). It looks like:

  <script async src="myAsyncScript.js" onload="myInit()"></script>
  <script defer src="myDeferScript.js" onload="myInit()"></script>

In the HTML 5 spec, onload must be supported by all HTML elements other than body and frameset. The WebKit blog also has some useful details.

Passing through the generic '#attributes' option might be the way to go, it would make add_js/css more flexible for future needs.

grendzy’s picture

Title: Add async property to script tags » Add async, onload property to script tags
Status: Needs work » Needs review
FileSize
3.26 KB

Status: Needs review » Needs work

The last submitted patch, 1140356_onload.patch, failed testing.

nod_’s picture

you should pull the new code, defer and async have been replaced by the usual attributes array.

bleen’s picture

nod_ does that mean this is fixed for D8? can we move this directly to backporting to D7?

grendzy’s picture

Version: 8.x-dev » 7.x-dev

Thanks, I tested D8, and array('attributes' => array('async' => TRUE, 'onload' => 'init()')) works now. The commit was #1664602: Allow attributes to be passed to drupal_add_[css|js] (SRI).

Gold’s picture

Status: Needs work » Needs review
FileSize
4.73 KB

This is a clean attempt at the d7 port of the d8 patch in #33. This is working on my system here at work.

This adds the following;

  • async attribute to <script> tags with an external source added using drupal_add_js()
  • async attribute to <script> tags with an internal source added using drupal_add_js()
  • simpleTest test for async being added to <script> tags with an external source
  • simpleTest test for async being added to <script> tags with an internal source
  • fixes simpleTest test for defer being added to <script> tags with an external source
  • fixes simpleTest test for defer being added to <script> tags with an internal source

Status: Needs review » Needs work

The last submitted patch, d7-add_async_attr-1140356-54.patch, failed testing.

Gold’s picture

Hmm... I can see why it failed, but I'm wondering why it didn't fail locally. :/ Checking into it again.

If I'm updating my own patch, what is the protocol? Can I edit the original comment, remove the fail and attach the, hopefully, workinng one?

update: and having tried editing the comment I see we can't update the attachment. I guess that answers that.

Gold’s picture

Okay, this is looking a bit more promising. Update to the patch at #54.

Gold’s picture

Status: Needs work » Needs review
FileSize
4.71 KB

Hmm... Does "Status: needs review" trigger the automated testing? And just in case it's related to the status and the attachment I'm attaching it again. This one and the one at #57 are the same.

Gold’s picture

Nuts... Both are queued for testing now. It is just the Status that matters. :)

On the upside, they passed the tests. :)

grendzy’s picture

Status: Needs review » Needs work

The patch works for async, but still needs support for onload.

Gold’s picture

Assigned: diggingrelic » Gold
Status: Needs work » Needs review
FileSize
6.21 KB

Update of #58. Added onload as requested in #60

This adds the following;

  • async attribute to <script> tags with an external source added using drupal_add_js()
  • async attribute to <script> tags with an internal source added using drupal_add_js()
  • onload attribute to <script> tags with an external source added using drupal_add_js()
  • onload attribute to <script> tags with an internal source added using drupal_add_js()
  • simpleTest test for async being added to <script> tags with an external source
  • simpleTest test for async being added to <script> tags with an internal source
  • simpleTest test for onload being added to <script> tags with an external source
  • simpleTest test for onload being added to <script> tags with an internal source
  • fixes simpleTest test for defer being added to <script> tags with an external source
  • fixes simpleTest test for defer being added to <script> tags with an internal source
mikeytown2’s picture

This feature has been integrated into AdvAgg. Patching of core is no longer required if one wishes to use async, onload or defer. I actually have an option (in advagg_mod) to turn on defer for all scripts and it will use onload to ensure that the js settings loads after drupal.js loads.

grendzy’s picture

Status: Needs review » Reviewed & tested by the community

Works as advertised, thanks!

nod_’s picture

#61: d7-add_async_attr-1140356-61.patch queued for re-testing.

David_Rothstein’s picture

Status: Reviewed & tested by the community » Needs review

So it would be great to get something committed for this, but this patch and #1664602: Allow attributes to be passed to drupal_add_[css|js] (SRI) (which was RTBC once before) are basically trying to do the same thing but in a different way.

We can only really commit one of them, so I think the people working on each issue should combine efforts and figure out which approach is best...

I'll leave a comment there too.

mgifford’s picture

Issue summary: View changes
Status: Needs review » Closed (duplicate)

Based on @David_Rothstein's comment above, there's more activity in the other issue, so I'm going to mark this as a duplicate only for that reason.

Feel free to re-open.

dooug’s picture

Adding duplicate ticket as related for easier reference.