51
Foot-Gun Features to Avoid in jQuery Dave Methvin, President, jQuery Foundation

jQuery Foot-Gun Features

Embed Size (px)

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.

Citation preview

Page 1: jQuery Foot-Gun Features

Foot-Gun Featuresto Avoid in jQuery

Dave Methvin, President, jQuery Foundation

Page 2: jQuery Foot-Gun Features
Page 3: jQuery Foot-Gun Features

• 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

Page 4: jQuery Foot-Gun Features

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."

Page 5: jQuery Foot-Gun Features

(builtwith.com)

Page 6: jQuery Foot-Gun Features

The jQuery Ecosystem• Code• Documentation• Developer expertise• Third-party plugins• MV* underpinning (Angular, Ember, Backbone, etc.)

Page 7: jQuery Foot-Gun Features

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

Page 8: jQuery Foot-Gun Features

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

Page 9: jQuery Foot-Gun Features
Page 10: jQuery Foot-Gun Features
Page 11: jQuery Foot-Gun Features

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"

Page 12: jQuery Foot-Gun Features

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>

Page 13: jQuery Foot-Gun Features

F A I L

Page 14: jQuery Foot-Gun Features

You Want the Latest? You Got It!

Page 15: jQuery Foot-Gun Features

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

Page 16: jQuery Foot-Gun Features

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

Page 17: jQuery Foot-Gun Features

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

Page 18: jQuery Foot-Gun Features

Forcing Layout

Page 19: jQuery Foot-Gun Features

All This Happens in 16 Milliseconds

From High Performance Browser Networking by Ilya Grigorik (O'Reilly)

Page 20: jQuery Foot-Gun Features

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");

Page 21: jQuery Foot-Gun Features

Performance

30 ms

Page 22: jQuery Foot-Gun Features

Chrome's Yellow Triangle

Page 23: jQuery Foot-Gun Features

Let's Change to Use a Class Instead

console.time("init");$("body").removeClass("activated");$("p.showing").css("color", "blue");console.timeEnd("init");

Page 24: jQuery Foot-Gun Features

Much Better!

8 ms

Page 25: jQuery Foot-Gun Features

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

Page 26: jQuery Foot-Gun Features

.show() and .hide()

Page 27: jQuery Foot-Gun Features

.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?

Page 28: jQuery Foot-Gun Features

Detached Elements?$("<span>Hi!</span>") .show() .appendTo("body");

Page 29: jQuery Foot-Gun Features

Elements Initially Hidden?<style> span { display: none; }</style>

$("<span>Hi!</span>") .show() .appendTo("body");

Page 30: jQuery Foot-Gun Features

Elements with Strange Display?<style> span { display: block; }</style>

$("<span>Hi!</span>") .show() .appendTo("body");

Page 31: jQuery Foot-Gun Features

Responsive Pages?<style> @media screen and (max-width: 700px) { #bar { display: none; } }</style>

$("#bar").show();

Page 32: jQuery Foot-Gun Features

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

Page 33: jQuery Foot-Gun Features

Global Settings in $.ajax()

Page 34: jQuery Foot-Gun Features

What Does This Code Do?$.ajax({ url: "file.txt", success: function(data){ alert(data);  }});

Page 35: jQuery Foot-Gun Features

Ok, NOW What does it do?$.ajaxSetup({ type: "POST", dataType: "json", timeout: 500 // ms!});

Page 36: jQuery Foot-Gun Features

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()

Page 37: jQuery Foot-Gun Features

Avoiding Ajax Annihilationfunction remoteCommand(options){ return $.ajax(   $.extend({ dataType: "json",

timeout: 1000, ... }, options) );}

Page 38: jQuery Foot-Gun Features

jQuery Constructor Foot-Guns• jQuery constructor takes a lot of "things"• $(function)• $(domelement)• $([ domelement, domelement … ])• $({ name: value, … })• $("htmlelement", { attribute: value })• $("selector")• $("html")

Page 39: jQuery Foot-Gun Features

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>";

Page 40: jQuery Foot-Gun Features

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()

Page 41: jQuery Foot-Gun Features

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

Page 42: jQuery Foot-Gun Features
Page 43: jQuery Foot-Gun Features

Avoid jQuery for Simple Things$("#toggle-checkboxes").on("click", function( event ) {

$(".cb").each(function() {

$(this).prop("checked", !$(this).prop("checked"));

});

});

Page 44: jQuery Foot-Gun Features

The Better Way$("#toggle-checkboxes").on("click", function( event ) {

$(".cb").each(function() {

this.checked = !this.checked;

});

});

Page 45: jQuery Foot-Gun Features

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!

Page 46: jQuery Foot-Gun Features

jQuery Custom Selectors• Extend the standard selectors• Aren't supported by the native querySelectorAll

method• That can make complex custom selectors slower

Page 47: jQuery Foot-Gun Features

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()

Page 48: jQuery Foot-Gun Features

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";

});

Page 49: jQuery Foot-Gun Features

Questions?Twitter: @davemethvinGithub: dmethvinEmail: [email protected]

Page 50: jQuery Foot-Gun Features

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;

  }

}

Page 51: jQuery Foot-Gun Features

Dead-Simple Plugin ArchitecturejQuery.fn.makeBlue = function() {

  return this.css("color", "blue");

}

$(".da-ba-de-da-ba-di").makeBlue();