WordPress.org

Make WordPress Core

Opened 6 years ago

Closed 16 months ago

Last modified 16 months ago

#12009 closed enhancement (worksforme)

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

Reported by: Otto42 Owned by: azaozz
Milestone: 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 4 years ago.

Download all attachments as: .zip

Change History (29)

#1 @scribu
6 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'

#2 @nacin
6 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.

#3 @ptahdunbar
5 years ago

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

#4 @azaozz
5 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.

#5 follow-up: @scribu
4 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

#6 @toscho
4 years ago

  • Cc info@… added

#7 @scep
4 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.

#8 @scep
4 years ago

  • Keywords needs-testing added

#9 in reply to: ↑ 5 @azaozz
4 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.

#10 follow-up: @toscho
4 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";

#11 @azaozz
4 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.

#12 in reply to: ↑ 10 ; follow-up: @scep
4 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.

#13 in reply to: ↑ 12 @scribu
4 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()).

#14 @wycks
4 years 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;

#15 @georgestephanis
4 years 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.

#16 @Otto42
4 years 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 4 years ago by Otto42 (previous) (diff)

#17 @scribu
4 years 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

#18 @ryanve
4 years 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 4 years ago by ryanve (next)

#19 @kevinlangleyjr
3 years ago

  • Cc kevinlangleyjr added

#20 @lkraav
3 years ago

  • Cc leho@… added

#21 @nacin
3 years ago

The 'script_loader_tag' should be added

I agree.

#22 @pothi
2 years ago

  • Cc pothi added

#23 @nacin
2 years ago

  • Component changed from JavaScript to Script Loader

#24 @webaware
2 years 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

#25 @SergeyBiryukov
2 years ago

#27672 was marked as a duplicate.

#26 @grapplerulrich
17 months ago

Could this be closed as the filter script_loader_tag has been added? #13592

#27 @wonderboymusic
16 months ago

  • Resolution set to fixed
  • Status changed from new to closed

#28 @ocean90
16 months ago

  • Milestone Future Release deleted
  • Resolution changed from fixed to worksforme
Note: See TracTickets for help on using tickets.