Using classes in JavaScript triggers a stylesheet invalidation, resulting in a hit on rendering performance. We should replace this usage wherever possible with using .data() instead. Functionally, things will be the same, but without invalidating stylesheets.

This is a meta issue to track down and make the following changes:

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

nod_’s picture

Status: Active » Needs review
FileSize
3.92 KB

Quick and dirty solution. We can't use $().data() because this needs to be exposed to CSS and other JS on the page and we can get away with native selectors so everything works out well. There is a slight perf impact, about 4/5ms on chrome compared to using classes but not a big deal compared to what's going on inside the functions that are called with .once() and considering we're not messing with the styling is a big plus.

Ideally I'd like to enforce the use of an id (so you can't call $().once(function () {});) and remove the function parameter so that once is only used for filtering a set of jQuery objects (so you can't do $().once('my-one-and-only', function () {}))

The only valid way to use once would then be:

$(selector).once('one-and-only').each(something)

// or

var $elements = $(selector).once('one-and-only');

That's how it's done in core now anyway.

If you ask me, the once thing ought to be a no-jQuery script.

nod_’s picture

Ah sorry removed the auto increment thing in that patch, didn't mean to. Anyway it's NW really.

nod_’s picture

Ok before we get into API changes of jQuery.once() here is an API-compatible version that uses the data-drupal-once attribute to do it's magic.

nod_’s picture

FileSize
4.4 KB

With the patch.

RobLoach’s picture

> We can't use $().data() because this needs to be exposed to CSS and other JS on the page

jQuery Once's job is simply to act on an element once. If CSS needs to react in a certain way, then it should add a specific class accordingly:
``` javascript
$('.myelement').once().addClass('specialcase');
```

Thanks for the pull request. Let's talk over there:
https://github.com/RobLoach/jquery-once/pull/5

Let's keep changes upstream, put out a release, and then update it here afterwards.

nod_’s picture

Status: Needs review » Postponed

Postponed on upstream.

droplet’s picture

recalculation of style??

I think it will:

for( var i = 0; i < 200; i++) {
 jQuery('a').addClass('active');
}

It won't

for( var i = 0; i < 200; i++) {
 jQuery('a').addClass('active' + i);
}

no active + i class in your stylesheets.

capynet’s picture

Re rolled.

sun’s picture

Status: Postponed » Needs work

The library has been changed upstream. We need to update our copy in core to the latest available code now.

Unless there is a tagged release already, it's fine if we're going to temporarily update to the latest master. — Since the change to upstream has not been battle-tested against real code/implementations, it's possible that we might even find bugs.

RobLoach’s picture

Title: Use data attributes instead of classes in .once() » Use data attributes instead of classes where
RobLoach’s picture

Title: Use data attributes instead of classes where » [META] Use data attributes rather than classes wherever possible
Issue summary: View changes
Status: Needs work » Active
Related issues: +#2348321: Upgrade to jQuery Once 2.x

Moving this to be a META issue for all the cases we find where .data() could/should be used.

LewisNyman’s picture

Issue tags: +frontend
nod_’s picture

dup of several other issues. Now jquery once uses data attributes too.