Slide 1

Slide 1 text

JAVASCRIPT FOR PHP DEVELOPERS

Slide 2

Slide 2 text

DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM @dcousineau

Slide 3

Slide 3 text

@croscon

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM BASICS

Slide 8

Slide 8 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM PRIMITIVE TYPES • number • string • boolean • object • array • null • undefined • NaN

Slide 9

Slide 9 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM OPERATIONS • Arithmetic • + - / * • Bitwise • & | ^ • Boolean • && || !

Slide 10

Slide 10 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM BOOLEAN OR var first = "truthy" || "something else"; //first == "truthy" var second = false || "something else"; //second == "something else";

Slide 11

Slide 11 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM TYPEOF • Returns variable type as a string

Slide 12

Slide 12 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM TYPEOF typeof true; //?? typeof 12; //?? typeof "string"; //?? typeof []; //?? typeof {}; //?? typeof NaN; //?? typeof null; //?? typeof undefined; //?? function Foo() {} typeof Foo; //??

Slide 13

Slide 13 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM TYPEOF typeof true; //"boolean" typeof 12; //"number" typeof "string"; //"string" typeof []; //"object" typeof {}; //"object" typeof NaN; //"number" typeof null; //"object" typeof undefined; //"undefined" function Foo() {} typeof Foo; //"function"

Slide 14

Slide 14 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM OBJECT OR ARRAY? var obj = {} , arr = []; typeof obj == typeof arr; //true obj instanceof Array; //false arr instanceof Array; //true

Slide 15

Slide 15 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM OBJECT OR ARRAY? // Is a given value an array? // Delegates to ECMA5's native Array.isArray _.isArray = Array.isArray || function(obj) { return Object.prototype.toString.call(obj) == '[object Array]'; };

Slide 16

Slide 16 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM NUMBERS Objects!

Slide 17

Slide 17 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM NUMBERS var integer = 5; var float = 0.567; var big = 1234567.89 float.toPrecision(2); //"0.57" big.toLocaleString("en-us") //"1,234,567.89" big.toLocaleString("nl-be") //"1.234.567,89"

Slide 18

Slide 18 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM STRINGS Objects!

Slide 19

Slide 19 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM STRINGS "Foo" + "Bar"; //"FooBar" var str = "Lorem Ipsum Dolor Sit Amet"; str.toLowerCase(); //"lorem ipsum dolor sit amet" str.toUpperCase(); //"LOREM IPSUM DOLOR SIT AMET" str.split(" "); //["Lorem", "Ispum", "Dolor", "Sit", "Amet"] str.substring(6,9); //"Ips" new String("Lorem Ipsum Dolor Sit Amet") == str; //true

Slide 20

Slide 20 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM STRINGS – NUMBERS parseInt("56"); //56 parseInt("42.567"); //42 parseInt("asdf"); //NaN parseInt("5a6"); //5 parseFloat("24.68"); //24.68 parseFloat("asdf"); //NaN parseFloat("24a"); //24

Slide 21

Slide 21 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM OBJECTS • “Dictionary” / “Associative Array” • key: value or 'key': value • Without ': A-Z0-9 only • Does not keep intrinsic ordering • Accessed keys using . (dot) or [] notation

Slide 22

Slide 22 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM OBJECTS var object = { foo: 'value', 'complex key': 0, bar: { nested: true } }; object.foo; //'value' object['complex key']; //0 object.bar.nested; //true object.bar['nested']; //true object['bar'].nested; //true object['bar']['nested']; //true

Slide 23

Slide 23 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM IN var test = { foo: 'value', bar: 'value', baz: 'value' } for (var key in test) { console.log(key + ": " + test[key]); } //PRINTS: //foo: value //bar: value //baz: value

Slide 24

Slide 24 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM ARRAYS • Special Object • Numeric ‘keys’ only • keeps intrinsic ordering

Slide 25

Slide 25 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM ARRAYS var arrayShort = [ 'one', 'two' ]; arrayShort[2] = 'three'; var arrayLong = new Array(); arrayLong[0] = 'one'; arrayLong[1] = 'two'; arrayLong[2] = 'three'; //arrayShort: ["one", "two", "three"] //arrayLong: ["one", "two", "three"]

Slide 26

Slide 26 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM ARRAYS var arr = [1,2,3,4,6]; arr.indexOf(2); //1 arr.join(':'); //"1:2:3:4:6" arr.pop(); //6 //[1,2,3,4] arr.push(7); //5 //[1,2,3,4,7] arr.reverse(); //[7,4,3,2,1] arr.shift(); //1 //[2,3,4,7] arr.unshift(8); //5 //[8,2,3,4,7] arr.slice(1); //[2,3,4,7] arr.slice(1,3); //[2,3] arr.slice(-3); //[3,4,7] arr.slice(-3,-1); //[3,4]

Slide 27

Slide 27 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM ARRAYS var arr1 = [1,2,3]; var arr2 = [3,4,5]; arr1.concat(arr2); //[1,2,3,3,4,5]

Slide 28

Slide 28 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM DELETE • Removes key from an object • Removes element from array

Slide 29

Slide 29 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM DELETE • Removes key from an object • Removes element from array just sets it to undefined!

Slide 30

Slide 30 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM DELETE + ARRAY var test = [0,1,2,3,4]; //[0, 1, 2, 3, 4] delete test[2]; for (var i in test) { console.debug(i); } //0, 1, 3, 4 for (var i = 0; i < test.length; i++) { console.debug(test[i]); } //0, 1, undefined, 3, 4 test.length; //5

Slide 31

Slide 31 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM FUNCTIONS • Objects! • Elevated • Used a named function before it is defined • func definitions are elevated to the top

Slide 32

Slide 32 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM FUNCTIONS function Foo() { //... } Foo(); //valid Bar(); //valid function Bar() { //... }

Slide 33

Slide 33 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM FUNCTIONS function Foo() { //... } Foo.bar = "value"; 'bar' in Foo; //true Foo.bar == "value"; //true

Slide 34

Slide 34 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM FUNCTION ARGUMENTS • No default arguments • Arguments are not required • unset arguments become undefined

Slide 35

Slide 35 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM ARGUMENTS • Special variable found in a function • A not-quite array object containing all arguments

Slide 36

Slide 36 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM ARGUMENTS function sum() { var x = 0; for (var i = 0; i < arguments.length; ++i) { x += arguments[i]; } return x; } sum(1, 2, 3); //6

Slide 37

Slide 37 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM COMPARISON • a == b / a != b • A and B compared by value alone • 1 == “1” evaluates to true • a === b / a !== b • A and B compared by value and type • 1 === “1” evaluates to false

Slide 38

Slide 38 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM WINDOW, DOCUMENT • Built in global objects in browser only • window • Provides access to browser window • Contains “global” variables • foo === window.foo • document • Provides access to current DOM

Slide 39

Slide 39 text

DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM FUNCTIONS

Slide 40

Slide 40 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM FUNCTIONS • First-Class • Can be assigned to variables, pass as arguments, and return as values • Anonymous • Do not require a name • Closures • “closes over” variables defined outside itself

Slide 41

Slide 41 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM CLOSURE function Foo() { var count = 0; return function() { count = count + 1; return count; }; } var bar = Foo(); bar(); //1 bar(); //2 bar(); //3

Slide 42

Slide 42 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM CLOSURE function Foo() { var count = 0; return function() { count = count + 1; return count; }; } var bar = Foo(); bar(); //1 bar(); //2 bar(); //3 var baz = Foo(); baz(); //??

Slide 43

Slide 43 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM CLOSURE function Foo() { var count = 0; return function() { count = count + 1; return count; }; } var bar = Foo(); bar(); //1 bar(); //2 bar(); //3 var baz = Foo(); count = 10; baz(); //??

Slide 44

Slide 44 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM CLOSURE function createAdder(amount) { return function(input) { return input + amount; }; } var add2 = createAdder(2); add2(2); //4 add2(8); //10 var add3 = createAdder(3); add3(3); //6 add3(7); //10

Slide 45

Slide 45 text

DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM SCOPING

Slide 46

Slide 46 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM HEADLINE • Functions only way to create new scopes • Variables defined with var are local • Variables defined WITHOUT var are global • In Browser: global variables are members of the window object

Slide 47

Slide 47 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM LOCAL & GLOBAL var outerScope = 10; var outerScope2 = 10; function Foo() { var outerScope = 20; var innerScope = 20; globalVariable = 30; outerScope2 = 40; } Foo(); alert(outerScope); //10 alert(outerScope2); //40 alert(innerScope); //error alert(globalVariable); //30

Slide 48

Slide 48 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM LEXICAL SCOPING function Foo() { var baz = 1; function Bar() { return baz; } return Bar(); } Foo(); //1 function Foo() { var baz = 1; return Bar(); } function Bar() { return baz; } Foo(); //baz is not defined

Slide 49

Slide 49 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM SCOPING function Outer() { myvar = "value1"; function Inner() { return myvar; } return Inner; } var inner = Outer(); inner(); //?? myvar = "value2"; inner(); //??

Slide 50

Slide 50 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM SCOPING function Outer() { myvar = "value1"; function Inner() { return myvar; } return Inner; } var inner = Outer(); inner(); //"value1" myvar = "value2"; inner(); //"value2"

Slide 51

Slide 51 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM HOISTING foo(); //called foo! function foo() { console.log('called foo!'); } foo(); //called foo! bar(); //undefined is not a function var bar = function() { console.log('called bar!'); } bar(); //called bar!

Slide 52

Slide 52 text

DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM THIS

Slide 53

Slide 53 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM THIS var Foo = { bar: "bar", baz: function() { return this.bar; } }; Foo.baz(); //"bar" Foo.bar = "bat"; Foo.baz(); //"bat" var baz = Foo.baz; baz(); //undefined

Slide 54

Slide 54 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM THIS var Foo = { bar: "bar", baz: function() { return this.bar; } }; Foo.bat = function() { return this.bar + "bat"; }; Foo.bat(); //"barbat"

Slide 55

Slide 55 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM CALL & APPLY var Foo = { bar: "bar", baz = function(param1, param2) { return this.bar + param1 + param2; } }; var Foo2 = { bar: "123" }; Foo.baz("baz", "bat"); //"barbazbat" Foo.baz.apply(Foo2, "baz", "bat"); //"123bazbat" Foo.baz.call(Foo2, ["baz", "bat"]); //"123bazbat"

Slide 56

Slide 56 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM BINDING! function bind(func, context) { return function() { return func.call(context, arguments); } }

Slide 57

Slide 57 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM THIS function RootLevelFunc() { console.debug(this); //?? }

Slide 58

Slide 58 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM THIS function RootLevelFunc() { console.debug(this); //undefined }

Slide 59

Slide 59 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM THIS Hello PHPBenelux! console.debug(this); //??

Slide 60

Slide 60 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM THIS Hello PHPBenelux! console.debug(this); //Window {top: Window, ...}

Slide 61

Slide 61 text

DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM EXCEPTIONS

Slide 62

Slide 62 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM EXCEPTIONS try { funcDoesNotExist(); } catch (e) { alert(e); //ReferenceError: funcDoesNotExist is not defined } finally { //Always Executes }

Slide 63

Slide 63 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM EXCEPTIONS function Foo() { throw new Error("Message"); } function Bar() { throw "Message"; } try { Foo(); } catch (e) { e.message == "Message"; //true } try { Bar(); } catch (e) { e == "Message"; //true }

Slide 64

Slide 64 text

DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM PROTOTYPE

Slide 65

Slide 65 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM HEADLINE function Foo() { //The "Constructor" } Foo.bar = function() { //A "Static" Function } Foo.prototype.baz = function() { //A "Method" }; Foo ‣ bar ‣ prototype ‣ baz ‣ constructor ‣ __proto__

Slide 66

Slide 66 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM HEADLINE var instance = new Foo(); instance.baz(); //works instance.bar(); //error Foo.bar(); //works Foo.baz(); //error Foo.prototype.baz(); //works instance ‣ __proto__ ‣ baz ‣ constructor ‣ __proto__ ‣ ...

Slide 67

Slide 67 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM HEADLINE instance.bat = function() { /* ... */ } instance.bat(); //works
 Foo.bat(); //error Foo.prototype.bat(); //error instance ‣ bat ‣ __proto__ ‣ baz ‣ constructor ‣ __proto__ ‣ ...

Slide 68

Slide 68 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM HEADLINE function Foo(baz) { this.baz = baz; } Foo.prototype.bar = function() { return this.baz; }; var foo1 = new Foo(1); var foo2 = new Foo(2); foo1.bar(); //1 foo2.bar(); //2 Foo.prototype.bar = function() { return this.baz * 2; }; foo1.bar(); //2 foo2.bar(); //4

Slide 69

Slide 69 text

DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM ASYNC

Slide 70

Slide 70 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM INTERVALS & TIMEOUTS var id = setInterval(function() { //Code to execute every 1000 milliseconds }, 1000); //clearInterval(id); to stop var id = setTimeout(function() { //Code to execute after 1000 milliseconds have passed }, 1000); //clearTimeout(id); to cancel

Slide 71

Slide 71 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM INTERVAL RACE CONDITIONS setInterval() setTimeout()

Slide 72

Slide 72 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM INTERVAL WORKAROUND var running = true; , interval = function() { if (!running) return; //do something if (running) setTimeout(interval, 1000); }; interval();

Slide 73

Slide 73 text

DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM DOM

Slide 74

Slide 74 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM DOM • Document Object Model • API to interact with browser’s representation of the HTML document

Slide 75

Slide 75 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM SELECTION document.getElementById('foo'); document.getElementsByClassName('.bar'); document.getElementsByTagName('script'); document.querySelectorAll('#foo .bar > script');

Slide 76

Slide 76 text

DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM

Slide 77

Slide 77 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM DOM: CREATION var paragraph = document.createElement('p'); var content = document.createTextNode("Lorem Ipsum"); paragraph.appendChild(content); paragraph.classList.add('my-class'); document.body.appendChild(paragraph);

Slide 78

Slide 78 text

DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM

Slide 79

Slide 79 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM DOM: LOADING SCRIPT var script = document.createElement('script'); script.src = "http://path.to/script.js"; script.async = true; var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(script, s);

Slide 80

Slide 80 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM DOM: ADDING IMAGE var img = document.createElement('img'); img.src = "http://path.to/some/image.jpeg"; img.onload = function() { /** do something on load */ }; document.body.appendChild(img);

Slide 81

Slide 81 text

DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM BROWSER TOOLS

Slide 82

Slide 82 text

SUBTITLE CHROME/SAFARI DEVEL. TOOLS

Slide 83

Slide 83 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM CONSOLE

Slide 84

Slide 84 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM BEWARE! • console.log is NOT BLOCKING • Sometimes value displayed is newer than value when log was called

Slide 85

Slide 85 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM NETWORK TAB & XHR • displays all network requests • Chrome is better for network debugging • Shows full request & response headers and data • Can replay XHR requests!

Slide 86

Slide 86 text

BREAK HAMMER TIME

Slide 87

Slide 87 text

DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM MODERN ARCH

Slide 88

Slide 88 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM HTML & DOM DOM: Object-Graph Representing Parsed HTML PRESENTATION LAYER HTML: The source

Slide 89

Slide 89 text

DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM PRESENTATION LAYER

Slide 90

Slide 90 text

DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM PRESENT ATION LAYER

Slide 91

Slide 91 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM CLASSIC JAVA GUI PROGRAMMING

Slide 92

Slide 92 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM CLASSIC JAVASCRIPT PROGRAMMING

Slide 93

Slide 93 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM CLASSIC JAVASCRIPT PROGRAMMING Just modify DOM What is the TextBox’s State Again? Start a jQuery animation

Slide 94

Slide 94 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM MODERN JS State DOM Events Controllers Modify Events Modify Javascript Read

Slide 95

Slide 95 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM WHERE IS YOUR DOM NOW? Everything is PUSHED into the DOM PRESENTATION LAYER

Slide 96

Slide 96 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM WHERE IS YOUR DOM NOW? Data FROM the DOM comes in via Events ONLY PRESENTATION LAYER

Slide 97

Slide 97 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM CONTROLLERS Update the DOM based on state Update State based on User Interaction

Slide 98

Slide 98 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM WIDGETS Pieces of functionality are self-contained Their State is self-contained

Slide 99

Slide 99 text

DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM

Slide 100

Slide 100 text

DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM underscorejs.org

Slide 101

Slide 101 text

DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM Functional, self-contained micro-library

Slide 102

Slide 102 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM FUNCTIONAL PROGRAMMING??? Functions are mappings between input and output • They have no side-effects • Input A always results in output b

Slide 103

Slide 103 text

+Functional Programming??? Daniel Cousineau // follow me : @dcousineau or http://dcousineau.com function input output global state global state global state X X X

Slide 104

Slide 104 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM UNDERSCORE.JS Collections •each •map •reduce •reduceRight •find •filter •reject •all •any •include •invoke •pluck •max •min •sortBy •groupBy •sortedIndex •shuffle •toArray •size Arrays •first •initial •last •rest •compact •flatten •without •union •intersection •difference •uniq •zip •indexOf •lastIndexOf •range Functions •bind •bindAll •memoize •delay •defer •throttle •debounce •once •after •wrap •compose Objects •keys •values •functions •extend •pick •defaults •clone •tap •has •isEqual •isEmpty •isElement •isArray •isObject •isArguments •isFunction •isString •isNumber •isFinite •isBoolean •isDate •isRegExp •isNaN •isNull •isUndefined Utility •noConflict •identity •times •mixin •uniqueId •escape •result •template Chaining •chain •value

Slide 105

Slide 105 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM MAP Maps function to each element in the input collection var inp = [1, 2, 3] , out = _.map(inp, function(n) { return n*2; }); //out = [2, 4, 6]

Slide 106

Slide 106 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM REDUCE Reduces collection to a single value. mem is the initial state, each successive iteration must be returned var inp = [1, 2, 3]; _(inp).reduce(function(mem, n){ return mem + n; }); //Iter 0: mem = 1 | n = 2 //Iter 1: mem = 3 | n = 3 //Returns: 6

Slide 107

Slide 107 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM PLUCK Iterates over a collection and extracts the values for the input key (assumes all elements in the collection are objects/ arrays) var stooges = [ {name: 'moe', age: 40} , {name: 'larry', age: 50} , {name: 'curly', age: 60} ]; _.pluck(stooges, 'name'); //Returns ["moe", "larry", "curly"]

Slide 108

Slide 108 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM MIN/MAX Returns the max item in a collection. If second argument (iterator) provided, will use to produce the value to be compared var stooges = [ {name: 'moe', age: 40} , {name: 'larry', age: 50} , {name: 'curly', age: 60} ]; _.max(stooges, function(s){ return s.age; }); //Returns {name: 'curly', age: 60}

Slide 109

Slide 109 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM KEYS Returns the keys from a dictionary as an array _.keys({ one: 1, two: 2, three: 3 }); //Returns ["one", "two", "three"]

Slide 110

Slide 110 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM DEFAULTS Maps a duplicate input dictionary on top of a predefined “default” dictionary var iceCream = { flavor: "chocolate" }; _.defaults(iceCream, { flavor: "vanilla" , sprinkles: "lots" }); //Returns {flavor : "chocolate", sprinkles : "lots"}

Slide 111

Slide 111 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM CHAINING When chain is initiated, method return a self-reference back to underscore but with the value attached [similar to opening with _(val)]. The chain continues until the value is extracted using .value() var stooges = [ {name: 'curly', age : 25}, {name: 'moe', age : 21}, {name: 'larry', age : 23} ]; var youngest = _.chain(stooges) .sortBy(function(s){ return s.age; }) .map(function(s){ return s.name + ' is ' + s.age; }) .first() .value(); //Returns "moe is 21"

Slide 112

Slide 112 text

DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM backbonejs.org

Slide 113

Slide 113 text

DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM micro-application framework

Slide 114

Slide 114 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM BACKBONE.JS • builds on jquery/Zepto and underscore.js • provides • views • models • collections • router

Slide 115

Slide 115 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM MODEL var OurModel = Backbone.Model.extend({ defaults: { foo: 'value' , bar: 1 } }); var instance = new OurModel(); instance.on('change:foo', function(modelobj, foo) { console.log('foo is now ' + foo); }); instance.set('foo', 'bat'); //foo is now bat

Slide 116

Slide 116 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM COLLECTION var OurModelCollection = Backbone.Collection.extend({ model: OurModel }); var inst1 = new OurModel() , inst2 = new OurModel() , coll = new OurModelCollection(); coll.on('add', function(modelobj) { console.log('Added model ' + modelobj.cid); }); coll.on('change:bar', function(modelobj, bar) { console.log('Bar for ' + modelobj.cid + ' is now ' + bar); }); coll.add(inst1); coll.add(inst2); inst1.set('bar', 'baz'); //Added model c4 //Added model c5 //Bar for c4 is now baz

Slide 117

Slide 117 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM VIEW var OurView = Backbone.View.extend({ className: 'our-view' , initialize: function() { this.listenTo(this.model, ’change:foo’, this.updateFoo, this); } , render: function() { this.updateFoo(); return this; } , updateFoo: function() { this.$el.html(this.model.get('foo')); } }); var modelInst = new OurModel({foo: 'bar'}); , viewInst = new OurView({model: modelInst}); $('#our-container').append(viewInst.render().el); modelInst.set('foo', 'baz'); //
bar
//
baz

Slide 118

Slide 118 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM ROUTER namespace.MessageCollectionRouter = Backbone.Router.extend({ routes: { "page/:page": "viewPage" } , initialize: function(options){ this.collection = options.collection; } , viewPage: function(page) { this.collection.setPage(page); } , setUrlToPage: function(page) { this.navigate('page/' + page, {trigger:false}); } }); Backbone.history.start({pushState: true, root: '/'});

Slide 119

Slide 119 text

DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM REFACTOR

Slide 120

Slide 120 text

Daniel Cousineau // follow me : @dcousineau or http://dcousineau.com Because you’re not lucky enough right now to start a project from scratch.

Slide 121

Slide 121 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM FIRST STEPS

Slide 122

Slide 122 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM LOOKING CONCEPTUALLY scaffolding DOM Management Event Management State Management Data Synchronization

Slide 123

Slide 123 text

Daniel Cousineau // follow me : @dcousineau or http://dcousineau.com var defaults = {/* ... */}; var methods = { init: function(options) { if (!$(this).is('textarea')) { $.error('Poster must be applied to a textarea'); return undefined; } options = _.defaults(options, defaults); var poster = new Poster(this, options); $(this).data('_poster', poster); return this; } }; $.fn.splash_poster = function(method) { //jQuery Plugin Boilerplate }; function Poster($el, options) { this.$el = $el; this.init(); } Poster.prototype.init = function() { var that = this; this.$el.on('change', jQuery.proxy(this.changeHandler, this)); this.$el.on('keyup', jQuery.proxy(this.changeHandler, this)); }; Poster.prototype.changeHandler = function(e) { //Check character counts, identify urls };

Slide 124

Slide 124 text

var defaults = {/* ... */}; var methods = { init: function(options) { if (!$(this).is('textarea')) { $.error('Poster must be applied to a textarea'); return undefined; } options = _.defaults(options, defaults); var poster = new Poster(this, options); $(this).data('_poster', poster); return this; } }; $.fn.splash_poster = function(method) { //jQuery Plugin Boilerplate }; function Poster($el, options) { this.$el = $el; this.init(); } Poster.prototype.init = function() { var that = this; this.$el.on('change', jQuery.proxy(this.changeHandler, this)); this.$el.on('keyup', jQuery.proxy(this.changeHandler, this)); }; Poster.prototype.changeHandler = function(e) { //Check character counts, identify urls }; scaffolding

Slide 125

Slide 125 text

var defaults = {/* ... */}; var methods = { init: function(options) { if (!$(this).is('textarea')) { $.error('Poster must be applied to a textarea'); return undefined; } options = _.defaults(options, defaults); var poster = new Poster(this, options); $(this).data('_poster', poster); return this; } }; $.fn.splash_poster = function(method) { //jQuery Plugin Boilerplate }; function Poster($el, options) { this.$el = $el; this.init(); } Poster.prototype.init = function() { var that = this; this.$el.on('change', jQuery.proxy(this.changeHandler, this)); this.$el.on('keyup', jQuery.proxy(this.changeHandler, this)); }; Poster.prototype.changeHandler = function(e) { //Check character counts, identify urls }; DOM Management

Slide 126

Slide 126 text

var defaults = {/* ... */}; var methods = { init: function(options) { if (!$(this).is('textarea')) { $.error('Poster must be applied to a textarea'); return undefined; } options = _.defaults(options, defaults); var poster = new Poster(this, options); $(this).data('_poster', poster); return this; } }; $.fn.splash_poster = function(method) { //jQuery Plugin Boilerplate }; function Poster($el, options) { this.$el = $el; this.init(); } Poster.prototype.init = function() { var that = this; this.$el.on('change', jQuery.proxy(this.changeHandler, this)); this.$el.on('keyup', jQuery.proxy(this.changeHandler, this)); }; Poster.prototype.changeHandler = function(e) { //Check character counts, identify urls }; Event Management

Slide 127

Slide 127 text

var defaults = {/* ... */}; var methods = { init: function(options) { if (!$(this).is('textarea')) { $.error('Poster must be applied to a textarea'); return undefined; } options = _.defaults(options, defaults); var poster = new Poster(this, options); $(this).data('_poster', poster); return this; } }; $.fn.splash_poster = function(method) { //jQuery Plugin Boilerplate }; function Poster($el, options) { this.$el = $el; this.init(); } Poster.prototype.init = function() { var that = this; this.$el.on('change', jQuery.proxy(this.changeHandler, this)); this.$el.on('keyup', jQuery.proxy(this.changeHandler, this)); }; Poster.prototype.changeHandler = function(e) { //Check character counts, identify urls }; State Management

Slide 128

Slide 128 text

var Poster = Backbone.View.extend({ tagName: 'form' , events: { "change textarea.message": "eChangeBody" , "keyup textarea.message": "eChangeBody" } , initialize: function() { this.render(); this.setModel(this.model); } , setModel: function(model) { this.model = model; this.listenTo(this.model, 'change:body', this.handleUpdateBody, this); this.handleUpdateBody(this.model, this.model.get('body')); } , handleUpdateBody: function(model, body) { this.$body.val(body).change(); } , eChangeBody: function(e) { //Check character counts, identify urls } , render: function() { this.$el.append(this._renderBody()); this.$body = this.$('textarea.message'); return this; } });

Slide 129

Slide 129 text

var Poster = Backbone.View.extend({ tagName: 'form' , events: { "change textarea.message": "eChangeBody" , "keyup textarea.message": "eChangeBody" } , initialize: function() { this.render(); this.setModel(this.model); } , setModel: function(model) { this.model = model; this.listenTo(this.model, 'change:body', this.handleUpdateBody, this); this.handleUpdateBody(this.model, this.model.get('body')); } , handleUpdateBody: function(model, body) { this.$body.val(body).change(); } , eChangeBody: function(e) { //Check character counts, identify urls } , render: function() { this.$el.append(this._renderBody()); this.$body = this.$('textarea.message'); return this; } }); Daniel Cousineau // follow me : @dcousineau or http://dcousineau.com scaffolding

Slide 130

Slide 130 text

var Poster = Backbone.View.extend({ tagName: 'form' , events: { "change textarea.message": "eChangeBody" , "keyup textarea.message": "eChangeBody" } , initialize: function() { this.render(); this.setModel(this.model); } , setModel: function(model) { this.model = model; this.listenTo(this.model, 'change:body', this.handleUpdateBody, this); this.handleUpdateBody(this.model, this.model.get('body')); } , handleUpdateBody: function(model, body) { this.$body.val(body).change(); } , eChangeBody: function(e) { //Check character counts, identify urls } , render: function() { this.$el.append(this._renderBody()); this.$body = this.$('textarea.message'); return this; } }); dom management

Slide 131

Slide 131 text

var Poster = Backbone.View.extend({ tagName: 'form' , events: { "change textarea.message": "eChangeBody" , "keyup textarea.message": "eChangeBody" } , initialize: function() { this.render(); this.setModel(this.model); } , setModel: function(model) { this.model = model; this.listenTo(this.model, 'change:body', this.handleUpdateBody, this); this.handleUpdateBody(this.model, this.model.get('body')); } , handleUpdateBody: function(model, body) { this.$body.val(body).change(); } , eChangeBody: function(e) { //Check character counts, identify urls } , render: function() { this.$el.append(this._renderBody()); this.$body = this.$('textarea.message'); return this; } }); ] event management

Slide 132

Slide 132 text

var Poster = Backbone.View.extend({ tagName: 'form' , events: { "change textarea.message": "eChangeBody" , "keyup textarea.message": "eChangeBody" } , initialize: function() { this.render(); this.setModel(this.model); } , setModel: function(model) { this.model = model; this.listenTo(this.model, 'change:body', this.handleUpdateBody, this); this.handleUpdateBody(this.model, this.model.get('body')); } , handleUpdateBody: function(model, body) { this.$body.val(body).change(); } , eChangeBody: function(e) { //Check character counts, identify urls } , render: function() { this.$el.append(this._renderBody()); this.$body = this.$('textarea.message'); return this; } }); state management

Slide 133

Slide 133 text

DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM
$('#widget .item a').click(function(e){ var $this = $(this) , $parent = $this.parent() , id = $parent.data('id'); $.ajax(/* … */); }); //...

Slide 134

Slide 134 text

DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM
$(function(){ var view = new Foo.Bar({el: $('#widget')}).render(); });

Slide 135

Slide 135 text

DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM (function(namespace, $){ namespace.Bar = Backbone.View.extend({ events: { 'click .item a': 'clickItemDelete' } , initialize: function() { } , render: function() { //... return this; } , clickItemDelete: function(e) { var $this = $(e.currentTarget) , $parent = $this.parent() , id = $parent.data('id'); $.ajax(/* … */); } }); })(window.Foo = window.Foo || {}, jQuery);

Slide 136

Slide 136 text

DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM MODULES

Slide 137

Slide 137 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM REQUIRE.JS define('MyModule', ['dependency', 'jquery'], function(Dep, $) { //Do Stuff return MyExports; }); require(['MyModule'], function(MyExports) { //Do Stuff With MyExports });

Slide 138

Slide 138 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM BROWSERIFY var Dep = require('dependency') , $ = require('jquery'); //Do Stuff module.exports = MyExports;

Slide 139

Slide 139 text

DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM BUILD

Slide 140

Slide 140 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM GULP var gulp = require('gulp'), uglify = require('gulp-uglify'), browserify = require('browserify'), hbsfy = require('hbsfy'), rename = require('gulp-rename'), jshint = require('gulp-jshint'), less = require('gulp-less'), sourcemaps = require('gulp-sourcemaps'), source = require('vinyl-source-stream'), buffer = require('vinyl-buffer'); gulp.task('default', ['watch'], function(){}); var rootPath = __dirname + '/static';

Slide 141

Slide 141 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM GULP gulp.task('watch', ['browserify', 'less-lays'], function() { gulp.watch(rootPath + '/js/**/*.js', ['browserify']); gulp.watch(rootPath + '/js/**/*.hbs', ['browserify']); gulp.watch(rootPath + '/less/**/*.less', ['less']); });

Slide 142

Slide 142 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM GULP gulp.task('browserify', function () { var b = browserify({ paths: [rootPath + '/js'], debug: true }); b.add(rootPath + '/js/__init__.js'); return b .transform(hbsfy) .bundle() .pipe(source('output.js')) .pipe(buffer()) .pipe(gulp.dest(rootPath + '/dist')) .pipe(uglify()) .pipe(rename({extname: '.min.js'})) .pipe(gulp.dest(rootPath + '/dist')); });

Slide 143

Slide 143 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM GULP gulp.task('less', function(){ gulp.src(rootPath + '/less/core.less') .pipe(sourcemaps.init()) .pipe(less()) .pipe(sourcemaps.write('.')) .pipe(gulp.dest(rootPath + '/css')); });

Slide 144

Slide 144 text

DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM PERF

Slide 145

Slide 145 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM PERFORMANCE Prefer singular built file Single HTTP request Single Cache Entry

Slide 146

Slide 146 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM PERFORMANCE Minify/Uglify Ensure comments dropped Pre-compile templates & Include in build gzip!

Slide 147

Slide 147 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM PERFORMANCE Preload as much data as possible Reduce round trips on load

Slide 148

Slide 148 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM PRELOAD Blueprint = window.Blueprint || {}; Blueprint._config = ...; Blueprint._current_user = ...; <?php if (isset($preload)): ?> Blueprint._preload = <?php echo json_encode($preload); ?>; <?php endif; ?>

Slide 149

Slide 149 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM PRELOAD /** * @param {Backbone.Model} model Model object to fill * @param {Function} identifier accepts model, raw preload: returns relevant data * @param {Function} success Triggers on successful preload or successful fetch * @param {Function} error Triggers on failed fetch */ preloadOrFetchModel: function(model, identifier, success, error) { if (Util.hasLocalPreloadData()) { var preload = Util.getLocalPreloadData() , preloadData = identifier(model, preload); if (preloadData) { model.set(preloadData, {silent: true}); success(); return; } } model.fetch({ success: success , error: error }); }

Slide 150

Slide 150 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM PERFORMANCE Prefer DOM updates to overwrites Make DOM changes in batches, small as possible Beware: Will this Repaint or Reflow? Prefer adding and removing classes

Slide 151

Slide 151 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM PERFORMANCE taking measurements forces reflow! Cache Measurements Measure only on browser events

Slide 152

Slide 152 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM PERFORMANCE var $ = require('jquery') , Backbone = require('backbone') , $window = $(window); var dim = _.extend({ window: { width: 0, height: 0 } , viewport: { top: 0, bottom: 0 } }, Backbone.Events); var resizeCallback = _.throttle(function() { dim.window.width = document.documentElement.clientWidth; dim.window.height = document.documentElement.clientHeight; dim.trigger('resize', dim); }, 1); var scrollCallback = _.throttle(function() { dim.viewport.top = $window.scrollTop(); dim.viewport.bottom = dim.viewport.top + dim.window.height; dim.trigger('scroll', dim) }, 1); // Singular browser event listener for resize and scroll events $window.on('resize.myapp-dim', resizeCallback); $window.on('scroll.myapp-dim', scrollCallback); module.exports = dim;

Slide 153

Slide 153 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM PERFORMANCE Animate in CSS Animate in CSS If not, animate using absolute or fixed positioning

Slide 154

Slide 154 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM PERFORMANCE var start = null; var element = document.getElementById("SomeElementYouWantToAnimate"); function step(timestamp) { if (!start) start = timestamp; var progress = timestamp - start; element.style.left = Math.min(progress/10, 200) + "px"; if (progress < 2000) { window.requestAnimationFrame(step); } } window.requestAnimationFrame(step);

Slide 155

Slide 155 text

DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM WHAT NEXT: ES6

Slide 156

Slide 156 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM PROMISES • fulfilled - Succeed • rejected - Failed • pending • settled - Completed

Slide 157

Slide 157 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM PROMISES var promise = new Promise(function(resolve, reject) { // do a thing, possibly async, then… if (/* everything turned out fine */) { resolve("Stuff worked!"); } else { reject(Error("It broke")); } });

Slide 158

Slide 158 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM PROMISES promise.then(function(result) { console.log(result); // "Stuff worked!" }, function(err) { console.log(err); // Error: "It broke" });

Slide 159

Slide 159 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM PRACTICAL var loaders = []; images.forEach(function(image, index){ //... var loader = $.Deferred(); loaders.push(loader); img.onload = function() { loader.resolve(); }; img.src = image.src; if (img.complete) { img.onload = null; loader.resolve(); } //... }); $.when.apply(null, loaders).done(hideLoader);

Slide 160

Slide 160 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM PRACTICAL var loaders = []; images.forEach(function(image, index){ //... loaders.push(new Promise(function(resolve, reject){ img.onload = function() { resolve(); }; img.src = image.src; if (img.complete) { img.onload = null; resolve(); } })); //... }); Promise.all(loaders).then(hideLoader);

Slide 161

Slide 161 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM YIELD function *foo() { yield 1; yield 2; } var it = foo(); console.log( it.next() ); // { value:1, done:false } console.log( it.next() ); // { value:2, done:false } console.log( it.next() ); // { value:undefined, done: true }

Slide 162

Slide 162 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM HEADLINE function *foo() { yield 1; yield 2; yield 3; yield 4; yield 5; yield 6; } for (var v of foo()) { console.log(v); } //1 2 3 4 5 6

Slide 163

Slide 163 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM LET/CONST const x = "value"; x = "another value"; //Error x; //"value" { let x; x = 5; x = 7; x; //7 } x; //"value"

Slide 164

Slide 164 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM FAT ARROW var adder = function(x) { return x + 1; } adder(1); //2 adder(2); //3 var fatAdder = (x) => x + 1; fatAdder(1); //2 fatAdder(2);

Slide 165

Slide 165 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM import User from 'user'; var evilTrout = new User(35); MODULES var localVariable = 123; export default function User(age) { this.age = age; };

Slide 166

Slide 166 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM import {sum, pi} from 'math'; console.log(sum(pi, pi)); MODULES export var pi = 3.141593; export function sum(x, y) { return x + y; };

Slide 167

Slide 167 text

THANKS. FOR YOUR ATTENTION DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM

Slide 168

Slide 168 text

DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM https://joind.in/13105

Slide 169

Slide 169 text

+ DANIEL COUSINEAU // FOLLOW ME : @DCOUSINEAU OR HTTP://DCOUSINEAU.COM ADDITIONAL RESOURCES • http://todomvc.com/ – Todo app written in popular frameworks • http://marionettejs.com/ – Extensions for Backbone.js