WordPress.org

Make WordPress Core

Opened 4 years ago

Last modified 3 weeks ago

#12009 new enhancement

Add support for HTML 5 "async" and "defer" attributes

Reported by: Otto42 Owned by: azaozz
Milestone: Future Release Priority: normal
Severity: normal Version:
Component: Script Loader Keywords: has-patch needs-testing
Focuses: Cc:

Description (last modified by scribu)

HTML5 supports async and defer attributes on script tags: http://www.w3.org/TR/html5/semantics.html#attr-script-async

Basic usage of these:

  • "async" scripts get executed asyncronously, as soon as they're loaded. This lets them run without slowing down the page parsing (normally, all page processing stops while the javascript code is executing).
  • "defer" scripts get deferred from running until page processing is complete. Sorta like jQuery(document).ready() does, except without pre-definitions. Faster, in other words, since it's built into the browser.

Correct usage would dictate that "libraries" like jQuery and such would get the async attribute, while bits of code that use the current DOM would get deferred. The defer bit is basically optional though, since most all code that exists uses something like jQuery(document).ready() already, when it's necessary, and so there's not a lot of benefit there.

The just released Firefox 3.6 supports the async attributes, so you can do testing with these immediately. I've noticed a speedup on the wp-admin side of things by using it, but I have not measured this and cannot be sure I'm not imagining it. Still, it does seem like it makes the page appear faster.

Attachments (1)

defer and async.patch (2.5 KB) - added by scep 2 years ago.

Download all attachments as: .zip

Change History (26)

comment:1 scribu4 years ago

  • Milestone changed from Unassigned to 3.0

We could add a new parameter to the script loader: load_type, with one of the following values:

  • (normal loading)
  • 'defer'
  • 'async'

comment:2 nacin4 years ago

  • Milestone changed from 3.0 to Future Release

This seems like a good idea to eventually do, but no patch or traction yet. Future release for now.

comment:3 ptahdunbar3 years ago

  • Cc trac@… added
  • Keywords needs-patch added

comment:4 azaozz3 years ago

This sounds good but to implement it and actually use it we would need at least the majority of the browsers in use to support it properly (as per the HTML5 specs). This seems to be "very far in the future" for now.

comment:5 follow-up: scribu2 years ago

  • Description modified (diff)

Alternatively, we could just add a filter to wp_print_scripts(), allowing users to add attributes when they need to.

As always, users find weird workarounds when the API doesn't oblige. For example, using the clean_url filter:

http://wordpress.stackexchange.com/a/38335/205

comment:6 toscho2 years ago

  • Cc info@… added

comment:7 scep2 years ago

  • Cc scep added
  • Keywords has-patch added; needs-patch removed

I was also looking for this feature, saw that it did not exist so i took a shot at it writing it in, I attached a patch for what I did.

scep2 years ago

comment:8 scep2 years ago

  • Keywords needs-testing added

comment:9 in reply to: ↑ 5 azaozz2 years ago

Replying to scribu:

As always, users find weird workarounds when the API doesn't oblige...

Agreed. However I'm still feeling a bit "uneasy" about adding support for a feature that is not supported by more than half of the browsers currently in use: http://en.wikipedia.org/wiki/Usage_share_of_web_browsers.

comment:10 follow-up: toscho2 years ago

These attributes are backwards compatible. I don’t think supporting them would do any harm.

But I don’t like more arguments for wp_register_script(). We have already four, that’s more than enough. How about a very simple extra string in WP_Scripts::do_item()?

$src = esc_url( apply_filters( 'script_loader_src', $src, $handle ) );
		
$extra = apply_filters( 'script_extra', '', $src, $handle );

if ( $this->do_concat )
	$this->print_html .= "<script type='text/javascript' src='$src' $extra></script>\n";
else
	echo "<script type='text/javascript' src='$src' $extra></script>\n";

comment:11 azaozz2 years ago

Yes, another filter would do the trick but has many drawbacks. If we decide to use these attributes in core, there will be no good way to add them: it will interfere with what plugins are adding (or removing) in all cases.

comment:12 in reply to: ↑ 10 ; follow-up: scep2 years ago

Replying to toscho:

These attributes are backwards compatible. I don’t think supporting them would do any harm.

But I don’t like more arguments for wp_register_script(). We have already four, that’s more than enough. How about a very simple extra string in WP_Scripts::do_item()?

I agree that since they are backwards compatible they should be supported.

I also agree that my patch adds a lot of extra arguments for the register and enqueue functions. I like you filter idea but it seems like it would lead to having a lot of code in the return function to identify which scripts should have extra info attached to them.

comment:13 in reply to: ↑ 12 scribu2 years ago

Replying to scep:

I also agree that my patch adds a lot of extra arguments for the register and enqueue functions. I like you filter idea but it seems like it would lead to having a lot of code in the return function to identify which scripts should have extra info attached to them.

Every script has a unique ID which it can be identified by (the first parameter to wp_enqueue_script()).

comment:14 wycks20 months ago

Here is the current Compatibility (Aug 2012):

Firefox: yes
Chrome: yes
Safari: yes
Andriod: yes
Blackberry: yes
IE version 10: yes


IE 6, 7, 8, 9: no

Opera: no (and no future plans)


http://caniuse.com/#search=async

ps. For reference the much used google analytic code uses async by setting var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;

comment:15 georgestephanis19 months ago

Leaving a comment to remind myself to come back and write a patch for this later. This is a great example of graceful degradation that probably should be supported.

comment:16 Otto4219 months ago

I like the patch, but instead of adding new params to the function calls, lets change the $in_footer parameter to be allowed as an array of attributes.

Basically, instead of $in_footer = false, have $attr = false.

For backward compatibility, you could do if $attr === true, then $attr = array('in_footer'=>true).

Then, you can have $attr = an array of the various settings, including potential future ones, allowing you to define whether it's in the footer or not, defer or not, async or not, etc.

Last edited 19 months ago by Otto42 (previous) (diff)

comment:17 scribu18 months ago

Or, we could just throw our hands in the air: add a 'script_loader_tag' and let plugins add whatever attributes they see fit: #13592

comment:18 ryanve18 months ago

The ideal way to handle script/style attributes is via #22249 because it is future-proof for any new attributes that are invented.

The 'script_loader_tag' should be added for consistency with the already existing 'style_loader_tag' to allow for customizations that go beyond attributes, such as wrapping in IE conditionals or adding inline scripts. (#13592 and #22245)

Version 0, edited 18 months ago by ryanve (next)

comment:19 kevinlangleyjr9 months ago

  • Cc kevinlangleyjr added

comment:20 lkraav8 months ago

  • Cc leho@… added

comment:21 nacin8 months ago

The 'script_loader_tag' should be added

I agree.

comment:22 pothi5 months ago

  • Cc pothi added

comment:23 nacin3 months ago

  • Component changed from JavaScript to Script Loader

comment:24 webaware2 months ago

A further complication: CloudFlare Rocketscript. This is a service that compresses and bundles scripts from your website into a single download. It does this by replacing your script elements with ones that look like this:

<script type='text/rocketscript' data-rocketsrc='http://example.com/path/to/src.js?ver=1.0'></script>

After the page has loaded, Rocketscript collects those elements all together and loads / executes the scripts. Which means scripts that don't like being loaded asynchronously break of course.

To disable Rocketscript for specific scripts, you can add an attribute data-cfasync="false" as per this support note:

https://support.cloudflare.com/hc/en-us/articles/200169436

However: it only works if the attribute comes before the src attribute.

So I like Toscho's solution, but with $extra added into the script element before the src attribute, not after it.

FYI: this is how I solved the problem for a plugin user, without such extra attribute support; nasty but effective. I'd love to offer a better solution :)

https://gist.github.com/webaware/8949605

comment:25 SergeyBiryukov3 weeks ago

#27672 was marked as a duplicate.

Note: See TracTickets for help on using tickets.