jQuery 3 - New Features and Performance Improvements

Abstract: This article talks about new features in jQuery 3 such as deferred, improved custom selectors, accelerated graphics, for..of, unwrap functionality, and security improvements.

jQuery is one of the most used cross-platform JavaScript libraries. Its main goal is to give developers a simple, fast and cross-browser substrate for DOM manipulation. jQuery is engineered to be extensible and lets us build our own jQuery plugins very quickly.

jQuery has three main versions:

· 1.x: currently at v. 1.12.4 and is the first generation jQuery library. It is to be used if you support Internet Explorer 6-8

· 2.x: currently at v. 2.2.4, the second generation drops Internet Explorer 6-8 support, it’s slimmer compared to its predecessor, and it offers the same API’s.

· 3.x: currently at v. 3.1.1, and the latest version of the library covered in this article. jQuery 3 was released in June 2016.

As of today, we can say that the jQuery foundation implements only jQuery 3.0. The previous versions are supported only for critical patches.

jQuery 3 has a slim build

Sometimes you may feel that jQuery has some features you don’t need in your application, the most common are jQuery ajax and animation that can be handled by other plugins. jQuery 3.0 now has a “slim” version that excludes these modules.

Let us discuss some salient features of this release.

Major changes in jQuery 3

Just like any typical major release of a library, jQuery 3 too has some improvements and bug fixes, which are as follows:

jQuery deferred

jQuery.Deferred objects have been updated for compatibility with Promises/A+ and ES2015 Promises.

An exception thrown in a .then() callback now is a rejection value. In previous jQuery versions, exceptions bubbled all the way up, aborting callback execution, and irreversibly locking both the parent and child Deferred objects.

The resolution state of a Deferred created by .then() is now controlled by its callbacks; exceptions become rejection values and return values of functions that are not a then become fulfillment values. In previous jQuery versions, returns from rejection handlers became rejection values.

Callbacks are always invoked asynchronously. In previous jQuery versions, they would be called immediately upon binding or resolution, whichever came last, with all the related pain (you know what I am saying).

Run this code in a browser and check the console. In jQuery 3, this will log “parent resolved” before invoking any callback, each child callback will then log “fulfilled child”, and the grandchildren will be rejected with Error “grandchild”.

In previous jQuery versions, this would log “rejected child” (the child Deferred having been rejected instead of fulfilled) once and then immediately terminate with uncaught Error “grandchild” (“parent resolved” not being logged and the grandchildren remaining unresolved).

jQuery.when has been updated too in order to accept any object that can be used in then callback, which includes native Promise objects.

If for some reason you can’t accept or change your code to follow this new, and a more precise way to handle promises, you can restore the previous behavior by replacing any use of .then() with the deprecated .pipe() method (which has an identical signature).

Added catch() to deferred

The catch() method was added to promise objects as an alias for .then(null, fn).

Other improvement in jQuery 3

Removed deprecated event register

Finally the deprecated load, unload and error, deprecated since jQuery 1.8; are now removed. Remember that the correct method to register an event handler in jQuery is on, and the opposite off.

Error cases exception

Previous jQuery versions always return “something” instead of throwing errors. This can be frustrating because an obvious logical error returns an empty result, which is difficult to handle appropriately.

jQuery 3 in similar scenarios now throws an exception, which can be handled accordingly.

Animation now use requestAnimationFrame

jQuery 3.0, if the browser supports it, uses requestAnimationFrame API to perform animations. The API uses GPU to perform animations. This method is powerful because it’s faster and smoother while performing animations, and on mobile devices, it’s a battery saver.

It is not the first time that jQuery developers have tried to use requestAnimationFrame for animations, but in order to apply it correctly, some code assumptions need to be refactored. The main problem is that requestAnimationFrame is not performed when the browser tab is not active, so jQuery must handle the animation stack correctly.

jQuery custom selectors speedup

jQuery offers some custom selectors (like :visible and :hidden) that apparently look like a CSS selector, but are resolved by jQuery selector engine.

The developers found that with these selectors, some extra work can be skipped if used multiple times in the same document. After they optimized it in jQuery 3, the result is now ~17 times faster.

:visible and :hidden custom selectors can still be expensive because they are based on how each browser implements the DOM flow rendering. This means that sometimes these selectors ask a complete flow recalculation of the whole page, so they must be used with responsibility.

jQuery 3.0 changes the meaning of :visible (and therefore of :hidden) selectors. Starting with jQuery 3.0, elements will be considered :visible if they have any layout boxes, including those of zero width and/or height. For example, br elements and inline elements with no content will be selected by the :visible selector.

unwrap() method

Until jQuery 3.0, the unwrap method did not take any argument.

The .unwrap() method removes the element's parent. This is effectively the inverse of the .wrap() method. The matched elements (and their siblings, if any) replace their parents within the DOM structure.

..will result at unwrapping all of them, but what if you need to unwrap only elements with a parent with row class? You need to change the selector in order to match its direct parent so do the following:

$('.row>.detail').unwrap();

With jQuery 3.0 a selector can be passed to the method in order to check the parent element. If an element parent does not match the selector, the element will not be unwrapped.

This is how it is done in jQuery 3:

$('.detail').unwrap('.row');

jQuery and Strict Mode

Today almost all modern browsers support strict mode. jQuery 3.0 has been developed with this in mind.

Strict mode makes several changes to normal JavaScript semantics. First, strict mode eliminates some JavaScript silent errors by changing them to throw errors. Second, strict mode fixes mistakes that make it difficult for JavaScript engines to perform optimizations: strict mode code can sometimes be made to run faster than identical code that's not strict mode. Third, strict mode prohibits some syntax likely to be defined in future versions of ECMAScript.

This does not imply that you have to rewrite your existing jQuery code. Although jQuery 3.0 has been written in strict mode, it’s not mandatory to have all your code strict mode compliant.

jQuery 3 opens the door to new features and performance advantages.

jQuery 3.0 supports the for…of statement. This iterator is part of ECMAScript 6. It gives a more readable way to loop over iterable objects, such as Arrays, Maps, and Sets. In jQuery 3.0, the for...of loop can be used to replace the $.each(...) usage.

Important note: The for...of loop will only work with browsers that supports ECMAScript 6

escapeSelector

jQuery 3.0 give us the new $.escapeSelector(). The method allows to escape characters that have a different usage as CSS selector, and result in a wrong selection.

Starting from this simple HTML code:

<body>
<div id="my:terrible.id">
</div>
</body>

Calling the selector given below, the element is not selected, because special characters must be escaped:

$('#my:terrible.id');

With jQuery 3.0 it can be selected like this

$('#'+$.escapeSelector('my:terrible.id'));

This method is particularly useful when a class name or an ID contains characters that have a special meaning in CSS, such as the dot or semicolon. Such characters usually occur in legacy applications or auto-generated code. Now instead of using escaping functions, we have the jQuery official one.

From MDN (https://developer.mozilla.org/it/docs/Glossary/Cross-site_scripting):

Cross-site scripting (XSS) is a security exploit which allows an attacker to inject into a website malicious client-side code. This code is executed by the victims and lets the attackers bypass access controls and impersonate users. According to the Open Web Application Security Project, XSS was the third most common Web app vulnerability in 2013.

This new layer requires the developers to specify dataType: 'script' in the options of $.ajax() and $.get() methods. Now when you make a request for a script on a domain different from yours, you must now explicitly declare this in the options.

get() and post() signature changes

jQuery get() and post() are shorthand for the ajax() function used often to simplify an Ajax call. In jQuery 1.0, the ajax() function can receive a set of key/value pairs that configure the Ajax request. This was not possible with get() and post().

jQuery 3.0 adds this signature for the $.get( ) and the $.post( ) in order to align them to $.ajax( ). Obviously the type option will be ignored and set accordingly from the shorthand function.

Very minimal SVG support

jQuery has never fully supported SVG and probably this will never change. With jQuery 3.0 methods for CSS class manipulation, .addClass(), .removeClass() and .hasClass() can now be used to manipulate SVG.

Prior to jQuery 3.0 you had to access class attribute as any other attribute, losing the power of jQuery class manipulation functions.

Now jQuery can be used to find an SVG element and style the classes with CSS.

Before jQuery 3, the jQuery library returned rounded int values with width(), height() and related methods. jQuery 3 now return a floating number; this is particularly relevant when you have to work with exact values on layout and DOM manipulation.

Starting from this simple HTML code:

<body>
<div id="row" style="width: 12.7px;">
</div>
</body>

..calling the following code, the result will be My width is: 13:

var myWidth=$('#row').width();
alert('My width is '+myWidth);

With jQuery 3 the width is returned considering the decimal part, so the result will be My width is: 12.7

Bind()/delegate() deprecated

With jQuery 3 the methods .bind(), .unbind(), .delegate() and .undelegate() are deprecated and they might be removed in future releases.

As said previously, the correct method to register an event handler is jQuery is on and the opposite off.

Conclusions

jQuery 3 brings in a lot of new features to the library. All the code needed to support legacy browsers is finally removed, and the code is reengineered to use and support modern features.

Was this article worth reading? Share it with fellow developers too. Thanks!

Irvin Dominin is currently working as lead of a technical team in SISTEMI S.p.A. (Turin, Italy) on .NET, jQuery and windows Projects. He is an active member on StackOverflow. You can reach him at: irvin[dot]dominin[attherate]gmail[dot]com or on LinkedIn

Feedback - Leave us some adulation, criticism and everything in between!