jquery foot-gun features
DESCRIPTION
This talk recaps some features and practices that are best to avoid in good jQuery pages and apps. Following these rules will improve performance and maintainability, and may prevent your co-workers from coming after you with sharp objects.TRANSCRIPT
Foot-Gun Featuresto Avoid in jQuery
Dave Methvin, President, jQuery Foundation
• We maintain jQuery code, and much more• We represent the web developer in
groups like the W3C and ECMA (JavaScript)• We encourage collaboration to avoid a
lot of "almost but not quite alike" solutions that can't play well together
Let's make standards work for us, solving real problems!
Web developer needs should be expressed early in the process, before a standard is deployed in browsers and it becomes "too late to fix it."
(builtwith.com)
The jQuery Ecosystem• Code• Documentation• Developer expertise• Third-party plugins• MV* underpinning (Angular, Ember, Backbone, etc.)
jQuery Evolves• jQuery 1.0 was released in 2006• Best practices in 2006 are not the same in 2014• Performance bottlenecks in 2014 also differ
jQuery Evolves, You Should Too• jQuery 1.0 was released in 2006• Best practices in 2006 are not the same in 2014• Performance bottlenecks in 2014 also differ
• Web development is evolving, and that's a good thing
Can't jQuery Just Fix It?• We fixed some of these problems in jQuery 1.9/2.0• By removing bad APIs and changing behavior
• It broke lots of code, and we knew it would• So we made the jQuery Migrate plugin
• Fixing the rest is up to you• "Please code responsibly"
Foot-Gun #1: jquery-latest.js• "How can I download the latest version of jQuery?"• http://code.jquery.com/jquery-latest.js• http://code.jquery.com/jquery-latest.min.js
• "Well I always want to run the latest version!"
<script src="http://code.jquery.com/jquery-latest.js"></script>
F A I L
You Want the Latest? You Got It!
jQuery's Hack to Save These Sites• Freeze the jQuery CDN jquery-latest files at version
1.11.1• Google CDN is freezing its /1/ "latest" version at 1.11.1
as well• So "latest" no longer means latest
How To Avoid This Foot-Gun• Include a specific version of jQuery• Test the site or app with that version• Upgrade and retest when needed
Features jQuery 1.9 Removed• http://jquery.com/upgrade-guide/1.9/• $.browser• Browser sniffing is a really bad idea!
• $(elements).live( … )• Handling events at the document level is slow, and doesn’t
work reliably for Apple touch events
• Use the jQuery Migrate plugin to find problems
Forcing Layout
All This Happens in 16 Milliseconds
From High Performance Browser Networking by Ilya Grigorik (O'Reilly)
Adventures in Dirty Layout• jQuery provides custom :visible and :hidden
selectors• They let you select elements based on the display
property of the element (or its ancestors, since display is inherited)• I came across an example similar to this in an event
handler
console.time("init");$("body").removeClass("activated");$("p:visible").css("color", "blue");console.timeEnd("init");
Performance
30 ms
Chrome's Yellow Triangle
Let's Change to Use a Class Instead
console.time("init");$("body").removeClass("activated");$("p.showing").css("color", "blue");console.timeEnd("init");
Much Better!
8 ms
Foot-Gun Avoidance Tactic• Probably best to avoid :visible and :hidden
altogether• But… don't use classes for strictly JavaScript-related
state• Use data- attributes or jQuery's .data() method instead• Eliminates inadvertent forced layouts or style recalculations
caused by class name changes
.show() and .hide()
.show() and .hide()• $("#abc").show() makes an element visible• $("#abc").hide() makes it invisible• Changes the element's style attribute to ensure it
"sticks"
What could possibly go wrong?
Detached Elements?$("<span>Hi!</span>") .show() .appendTo("body");
Elements Initially Hidden?<style> span { display: none; }</style>
$("<span>Hi!</span>") .show() .appendTo("body");
Elements with Strange Display?<style> span { display: block; }</style>
$("<span>Hi!</span>") .show() .appendTo("body");
Responsive Pages?<style> @media screen and (max-width: 700px) { #bar { display: none; } }</style>
$("#bar").show();
Avoid the Hide/Show Foot-Gun• Always use classes to show or hide elements• Prevents edge cases with forcing display inline• Doesn’t get elements “stuck” in some state• Works with responsive pages
Global Settings in $.ajax()
What Does This Code Do?$.ajax({ url: "file.txt", success: function(data){ alert(data); }});
Ok, NOW What does it do?$.ajaxSetup({ type: "POST", dataType: "json", timeout: 500 // ms!});
Global Settings BAD• Impossible to tell at the call point what the code really
does• Difficult for modular code (plugins) to work
consistently• So don't use $.ajaxSetup()
Avoiding Ajax Annihilationfunction remoteCommand(options){ return $.ajax( $.extend({ dataType: "json",
timeout: 1000, ... }, options) );}
jQuery Constructor Foot-Guns• jQuery constructor takes a lot of "things"• $(function)• $(domelement)• $([ domelement, domelement … ])• $({ name: value, … })• $("htmlelement", { attribute: value })• $("selector")• $("html")
What Does This Do?$(selector).appendTo("body");
Don't be fooled by the selector variable name; it could be any of the cases shown in the previous slide.
var selector = "<script>alert(42)</script>";
Lots of jQuery APIs Insert HTML• That's why you use them, it's not a jQuery bug• But it can be a foot-gun• If you want to only set literal text, use .text()
Don’t Blindly Trust User/URL Data!• Data from the URL can be massaged by an attacker to
steal the user's session or data and do things on a user's behalf
Avoid jQuery for Simple Things$("#toggle-checkboxes").on("click", function( event ) {
$(".cb").each(function() {
$(this).prop("checked", !$(this).prop("checked"));
});
});
The Better Way$("#toggle-checkboxes").on("click", function( event ) {
$(".cb").each(function() {
this.checked = !this.checked;
});
});
Instead of $(this) … Use this!
$(this).is(“:checked”) this.checked
$(this).prop(“checked”) this.checked
$(this).is(“:disabled”) this.disabled
$(this).attr(“id”) this.id
$(this).attr(“class”) this.className
Shorter, Faster, and Prettier, Too!
jQuery Custom Selectors• Extend the standard selectors• Aren't supported by the native querySelectorAll
method• That can make complex custom selectors slower
jQuery Selector Equivalents:checkbox, :radio, :text, :image, :file, :reset
input[type=X]
:button button, input[type=button]
:header h1, h2, h3, h4, h5
:first :first-child or .first()
:last :last-child or .last()
Be Careful About Native Methods$("div").on("click", function( event ) {
// Throws an error in IE8 or the Android 2.x browser
this.className.add("clicked");
// Works everywhere
$(this).addClass("clicked");
// Works everywhere if you can clobber className
this.className = "clicked";
});
Questions?Twitter: @davemethvinGithub: dmethvinEmail: [email protected]
Powerful API$(".msg").addClass("unread");
compared to
var unreadClass = "unread",
msgs = document.getElementsByClassName("msg");
var cls = new RegExp("\\b"+unreadClass+"\\b");
for ( var i=0; i < msgs.length; i++ ) {
if ( !cls.test(msgs[i]) {
msgs[i].className += " "+unreadClass;
}
}
Dead-Simple Plugin ArchitecturejQuery.fn.makeBlue = function() {
return this.css("color", "blue");
}
$(".da-ba-de-da-ba-di").makeBlue();