81
DevGeekWeek 2017 18-22 ביוני2017 | מלון דניאל, הרצליה08:00 – 09:00 רישום וארוחת בוקר10:30 09:00 הרצאות סמינרים10:30 – 10:45 הפסקה12:30 10:45 הרצאות סמינרים12:30 – 13:30 ארוחת צהריים15:00 13:30 הרצאות סמינרים15:00 – 15:15 הפסקה מתוקה16:30 15:15 הרצאות סמינרים

DevGeekWeek 2017 - John Brycemarketing.johnbryce.co.il/ad/2017/DevGeekWeek/44046.pdfDevGeekWeek 2017 הילצרה ... Building Web Applications using AngularJS Programming Embedded

Embed Size (px)

Citation preview

DevGeekWeek 2017

| מלון דניאל, הרצליה 2017ביוני 18-22

רישום וארוחת בוקר 09:00 – 08:00

הרצאות סמינרים 09:00– 10:30

הפסקה 10:45 – 10:30

הרצאות סמינרים 10:45– 12:30

ארוחת צהריים 13:30 – 12:30

הרצאות סמינרים 13:30– 15:00

הפסקה מתוקה 15:15 – 15:00

הרצאות סמינרים 15:15– 16:30

לפרטים והרשמה צרו קשר:[email protected] | 03-7100791 - לידיה

www.jbh.co.il | !תהיו חברים

שפות התכנות וכלי הפיתוח מתחדשים ומתעדכנים בקצב חסר תקדים ושולטים בכל תעשייה אשר נדרשת להתחרות בעולם המודרני והמקושר. התעדכנות טכנולוגית שוטפת תבטיח בחירה נכונה של כלים ושירותים אשר יובילו לפיתוח קוד מהיר, יעיל ואיכותי, תוך שמירה על גמישות והתאמה לחידושים טכנולוגיים עתידיים.

ג'ון ברייס הדרכה מציעה מגוון עצום של קורסים מבוקשים וייחודיים לקהל הרחב ולקהל המקצוענים.

זמן לפתח >זמן להתפתח... <

קורסי הפיתוח של ג'ון ברייס הדרכה

Java Programming Extreme JavaReal-time web applications with Node.js and Express.jsFront End Development with HTML5, CSS3 & jQueryBuilding Web Applications using AngularJSProgramming Embedded LinuxDeveloping Web/Mobile Applications using ASP.NET MVC 4/5 and jQueryLinux InternalsPython 2 ProgrammingDeveloping Android applicationsAngular 2.0Java Script Full Stack ExpertsProgramming the .NET Framework 4.0/4.5 with C# 5.0

69474359337642584335791100137359134083251050 3377457970240

שם הקורסמק”ט

לפרטים נוספים ושליחת קו"ח פנו אל:Talent Recuitment Manager ,מאיה הוף

054-4601413 | [email protected]

אנחנו מרחיבים את סגל המרצים שלנוונשמח לקלוט אותך לשורותינו

אפשרויות תעסוקה מגוונות | משרה גמישה בוקר/ערב | אפשרות לעבודה כפרילאנס

Big Data Cyber DevOps

בואו לגדול איתנויש לנו נבחרת מרצים מנצחת!

ולהעביר הלאה את הידע המקצועי שלכם!

ג’ון ברייס מחפשת את הטאלנט הבא

AWS Cloud Dev Full StackBig Data Cyber AndroidDevOps

למגוון המשרות חפשו בגוגל "מרצים בג'ון ברייס"

Advanced JavaScript Patterns and Techniques

Agenda

• Interfaces in JavaScript• JavaScript Design Patterns• JavaScript Best Practices and Performance Tips• Structuring Web Applications

1

Interfaces

• The interface is one of the most useful tools in the object-oriented JavaScript programmer’s toolbox

• One of the basic principles of the GOF’s Design Patterns says “Program to an interface, not an implementation”

• The problem is that JS has no built-in way of creating or implementing interfaces

Emulating Interface in JavaScript

• Three ways of emulating interfaces in JavaScript:o Commentso Attribute checkingo Duck typing

2

Describing Interface with Comments

• The easiest and least effective way of emulating an interface is with comments

• Mimicking the style of other object-oriented languages, the interface and implements keywords are used but are commented out so they don’t cause syntax errors

Describing Interface with Comments

/*interface Composite {

function add(child);function remove(child);function getChild(index);

}

interface FormItem {function save();

}

*/

3

Describing Interface with Commentsfunction CompositeForm(id) { // implements Composite, FormItem

};

// Implement the Composite interfaceCompositeForm.prototype.add = function(child) {

};CompositeForm.prototype.remove = function(child) {

};CompositeForm.prototype.getChild = function(index) {

};

// Implement the FormItem interfaceCompositeForm.prototype.save = function () {

};

• The second technique is a little stricter• All classes explicitly declare which interfaces

they implement, and these declarations can be checked by objects wanting to interact with these classes

Emulating Interfaces with Attribute Checking

4

function CompositeForm(id) { // implements Composite, FormItemthis.implementsInterfaces = ['Composite', 'FormItem'];

};

// A function that requires its argument to implement certain interfacesfunction addForm(formInstance) {

if (!implements(formInstance, 'Composite', 'FormItem')) {throw new Error("Object doesn't implement the required interfaces");

}}

Emulating Interfaces with Attribute Checking

Emulating Interfaces with Attribute Checking// Check to see if an objects declares that it implements the required interfacesfunction implements(object) {

for (var i = 1; i < arguments.length; i++) {var interfaceName = arguments[i];var interfaceFound = false;for (var j = 0; j < object.implementsInterfaces.length; j++) {

if (object.implementsInterfaces[j] == interfaceName) {interfaceFound = true;break;

}}if (!interfaceFound) {

return false;}

}return true; // all interfaces were found

}

5

• The main drawback of this approach is that you are not ensuring that the class really does implement this interface

• You only know if it says it implements it• It is very easy to create a class that declares it

implements an interface and then forget to add a required method

Emulating Interfaces with Attribute Checking

Emulating Interfaces with Duck Typing

• “If it walks like a duck and quacks like a duck, it’s a duck”

• The idea is simple: if an object contains methods that are named the same as the methods defined in your interface, then it implements that interface

6

Interface Helper Class

• We will use the Interface helper class and the class method Interface.ensureImplements to perform explicit checking of methods

Interface Helper Classpfunction Interface(name, methods) {

this.name = name;this.methods = methods;

}

// Static class methodInterface.ensureImplements = function (object) {

for (var i = 1; i < arguments.length; i++) {var interface = arguments[i];if (interface.constructor !== Interface) {

throw new Error("Arguments must be instances of Interface");}for (var j = 0; j < interface.methods.length; j++) {

var method = interface.methods[j];if (!object[method] || typeof object[method] !== 'function') {

throw new Error("Object does not implement the " + interface.name+ " interface. Method " + method + " was not found.");

}}

}};

7

Using the Interface Classvar Composite = new Interface('Composite', ['add', 'remove', 'getChild']);var FormItem = new Interface('FormItem', ['save']);

function CompositeForm(id) { // implements Composite, FormItem

};// Implement the Composite interfaceCompositeForm.prototype.add = function (child) {

};…// A function that requires its argument to implement certain interfacesfunction addForm(formInstance) {

Interface.ensureImplements(formInstance, Composite, FormItem);...

}

JavaScript Design Patterns

• What are Design Patterns?• Design Patterns in JavaScript• Singleton• Factory• Decorator• Strategy• Proxy• Observer

8

What are Design Patterns?

• Design Patterns harness object orientation to promote reusability, extensibility and ease of maintenance.

• “Design patterns are recurring solutions to design problems you see over and over.” (The Smalltalk Companion, James W. Cooper)

• The 23 Gang of Four (GoF) patterns are generally considered the foundation for all other patterns.

What are Design Patterns?

• Most patterns and design principles address issues of change in software.

• Most patterns allow some part of a system to vary independently of other parts.

• Patterns provide a shared language among developers.

• Patterns don’t give you code, they give you experience.

9

Design Patterns in JavaScript• There are three main reasons why you would want to use

design patterns in JavaScript:• Maintainability – design patterns help to keep your modules

more loosely coupled. This makes it easier to refactor your code and to collaborate with other programmers in the team.

• Communication – design patterns provide a common vocabulary for dealing with different types of objects.

• Performance – some of the patterns can drastically improve the speed at which your program runs and reduce the amount of code you need to transmit to the client (The Proxy and Flyweight patterns are good examples of this)

Singleton Pattern

-Singleton()+Instance()

-instance: SingletonSingleton

return unique instance

Ensure a class has only one instance and provide a global point of access to it.

10

Singleton

• The singleton pattern is probably the simplest and most common pattern in JavaScript

• To create a singleton in JavaScript, all you really need to do is create an object literal

Singleton

• Advantages of using a singleton in JavaScript:� Encapsulation of members & functions� Creates its own Namespace� A singleton is a single instance object� Encourages code reuse� Organize your code in consistent manner

11

Example: Basic Singleton

// Basic Singletonvar Singleton = {

attribute1: 10,attribute2: true,

method1: function () {return this.attribute1 * 2;

},method2: function (arg) {

alert("method2, arg: " + arg);}

};

Singleton with Private Members

• You can define private members within a singleton object by creating a closure

• You can add variables and functions to the body of the singleton’s constructor (without the this keyword) to make them private

• Because a singleton is only instantiated once, you don’t have to worry about how many instances will be created from the methods and attributes declared within the constructor

• This particular singleton pattern is also known as the module pattern, referring to the fact that it modularizes and namespaces a set of related methods and attributes

12

Example: Singleton with Private Members// Singleton with Private Membersvar Singleton2 = (function () {

// Private membersvar privateAttribute1 = 5;var privateAttribute2 = [1, 2, 3];

function privateMethod1() {alert("privateMethod1");

}

return { // Public memberspublicAttribute1: 10,publicAttribute2: true,publicMethod1: function () {

return privateAttribute1 + this.publicAttribute1;},publicMethod2: function (arg) {

alert("publicMethod2, arg: " + arg);}

}})();

Example: Using the Singleton

Singleton2.publicAttribute1 = 20;result = Singleton2.publicMethod1();alert("Singleton2 result: " + result);

13

Lazy Instantiation

• If you have a singleton that is expensive to create, or resource-intensive, it makes more sense to defer its instantiation until it is needed

• A lazy loading singleton must be accessed through a static method, usually called getInstance()

• The getInstance() method checks whether the singleton has been instantiated• If it hasn’t, it is instantiated and returned• If it has, a stored copy is returned instead

Example: Lazy Initialization// Lazy loading singletonvar Singleton3 = (function () {

var uniqueInstance; // Private attribute that holds the single instnace

function constructor() {// Private membersvar privateAttribute1 = 5;

return { // Public memberspublicAttribute1: 10, publicMethod1: function () {

return privateAttribute1 + this.publicAttribute1;}

}}

return {getInstance: function () {

if (!uniqueInstance) {uniqueInstance = constructor();

}return uniqueInstance;

}}

})();

14

Example: Using the Singleton

Singleton3.getInstance().publicAttribute1 = 8;result = Singleton3.getInstance().publicMethod1();alert("Singleton3 result: " + result);

Factory Pattern

Product

ConcreteProduct

+FactoryMethod()+AnOperation()

Creator

+FactoryMethod()

ConcreteCreator

return new ConcreteProduct

product = FactoryMethod()

Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.

15

Factory Pattern

• The factory pattern helps decoupling two classes

• When one class needs to create an instance from another class, instead of using the new keyword and the class constructor, you can use a method that decides which specific class to instantiate

Example: Documentsvar Document = new Interface('Document', ['open', 'print']);

var WordDocument = function () { // implements Document};

WordDocument.prototype.open = function (path) { alert("Opening word document: " + path);

};

WordDocument.prototype.print = function () {alert("Printing word document");

};

var ExcelDocument = function () { // implements Document};

ExcelDocument.prototype.open = function (path) {alert("Opening excel document: " + path);

};

ExcelDocument.prototype.print = function () {alert("Printing excel document");

};

16

Example: Factoriesvar DocumentFactory = new Interface('DocumentFactory', ['createDocument']);

// WordDocumentFactory classvar WordDocumentFactory = function () { // implements DocumentFactory};

WordDocumentFactory.prototype.createDocument = function () {return new WordDocument();

}

// ExcelDocumentFactory classvar ExcelDocumentFactory = function () { // implements DocumentFactory};

ExcelDocumentFactory.prototype.createDocument = function () {return new ExcelDocument();

}

Example: Use Factoryfunction createDocuments(documentFactory) {

Interface.ensureImplements(documentFactory, DocumentFactory);

var doc1 = documentFactory.createDocument();doc1.open("doc1");doc1.print();

var doc2 = documentFactory.createDocument();doc2.open("doc2");doc2.print();

}

$(document).ready(function () {$('#btnCreateDocuments').click(function () {

var docType = $('#docType').val();var documentFactory = eval("new " + docType + "()");createDocuments(documentFactory);

});});

17

Decorator Design Pattern

Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.

+Operation()

Component

+Operation()

ConcreteComponent

+Operation()

Decorator

+Operation()-addedStateConcreteDecoratorA

+Operation()+AddedBehavior()

ConcreteDecoratorB

component.Operation()

base.Operation();AddedBehavior();

Example: Componentsp p// The Beverage interfacevar Beverage = new Interface('Beverage', ['print']);

// Tea classvar Tea = function() { // implements Beverage

}

Tea.prototype.print = function () {return "Tea";

}

// Coffee classvar Coffee = function(){ // implements Beverage

}

Coffee.prototype.print = function () {return "Coffee";

}

18

Example: Decorator

// The BeverageDecorator abstract decorator classvar BeverageDecorator = function(beverage) { // implements Beverage

Interface.ensureImplements(beverage, Beverage);this.beverage = beverage;

}

Example: Concrete Decorators// SugaredBeverage classvar SugaredBeverage = function(beverage) { // implements Beverage

BeverageDecorator.call(this, beverage); // call superclass's c'tor}extend(SugaredBeverage, BeverageDecorator);SugaredBeverage.prototype.print = function () {

return this.beverage.print() + '\n with Sugar';}

// MilkedBeverage classvar MilkedBeverage = function(beverage) { // implements Beverage

BeverageDecorator.call(this, beverage); // call superclass's c'tor}extend(MilkedBeverage, BeverageDecorator);MilkedBeverage.prototype.print = function () {

return this.beverage.print() + '\n with Milk';}

19

Decorator Example: Usage

var coffee = new Coffee(); var b1 = new SugaredBeverage(coffee);alert(b1.print());

var b2 = new MilkedBeverage(new SugaredBeverage(new Tea()));alert(b2.print());

Strategy Design Pattern

Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.

+ContextInterface()

Context

+AlgorithmInterface()

Strategy

+AlgorithmInterface()

ConcreteStrategyA

+AlgorithmInterface()

ConcreteStrategyB

+AlgorithmInterface()

ConcreteStrategyC

20

Example: Sort Strategies

// The SortStrategy interfacevar SortStrategy = new Interface('SortStrategy', ['sort']);

// SuickSort classvar QuickSort = function() { // implements SortStrategy

}

QuickSort.prototype.sort = function (arr, comparison) {return arr.sort(comparison);

}

Example: Sort Strategies

// MergeSort classvar MergeSort = function() { // implements SortStrategy

}

MergeSort.prototype.sort = function (arr, comparison) {if (!comparison) {

comparison = function (x, y) { return x > y ? 1 : (x == y ? 0 : -1); }

}var result = merge_sort(arr, comparison);copyArr(result, arr);

}

21

Example: Sort Strategiesfunction merge_sort(arr, comparison) {

if (arr.length < 2)return arr;

var middle = Math.ceil(arr.length / 2);return merge(merge_sort(arr.slice(0, middle), comparison),

merge_sort(arr.slice(middle), comparison), comparison);}

function merge(left, right, comparison) {var result = new Array();while ((left.length > 0) && (right.length > 0)) {

if (comparison(left[0], right[0]) <= 0)result.push(left.shift());

elseresult.push(right.shift());

}while (left.length > 0)

result.push(left.shift());while (right.length > 0)

result.push(right.shift());return result;

}

Example: Using the Strategy// StudentList classvar StudentList = function (sortStrategy) {

this._list = new Array();this._sortStrategy = sortStrategy;

}

StudentList.prototype.setSortStrategy = function (sortStrategy) {this._sortStrategy = sortStrategy;

}

StudentList.prototype.add = function (name) {this._list.push(name);

}

StudentList.prototype.print = function () {alert(this._list);

}

StudentList.prototype.sort = function () {this._sortStrategy.sort(this._list);

}

22

Example: Typical Usevar students = new StudentList(new QuickSort());

students.add("Shimon");students.add("Anna");students.add("Moshe");students.add("Roi");students.add("Ran");

students.sort();students.print();

students.add("Inbar");students.add("Ofir");students.setSortStrategy(new MergeSort());students.sort();students.print();

Proxy Design Pattern

Client

+Request()

Subject

+Request()

RealSubject

+Request()

Proxy

realSubject.Request()

Provide a surrogate or placeholder for another object to control access to it.

23

Proxy Design Pattern

• A proxy is an object that can be used to control access to another object

• A proxy object implements the same interface as the real subject

• The real subject actually performs the needed task• A proxy can be instantiated in place of this real

subject and allow it to be accessed remotely

Proxy Types• There are many uses for the proxy design pattern.• Five of the more common types of proxy are:

� Cache Proxy� Protection Proxy� Remote Proxy� Smart Proxy� Virtual Proxy

24

Cache Proxy• A cache proxy improves the performance of the underlying

object's members when they perform long-running tasks that return seldom-changing results.

• For example, the underlying object may provide a method that calculates prime numbers.

• When the first call to the proxy's matching method is made, the call is passed to the real object.

• The results from the call are stored within the proxy object and returned to the client.

• For subsequent calls, the cached information in the proxy can be returned without recalculating the prime numbers.

Example: Real Subject

var IPrimeChecker = new Interface('PrimeChecker', ['isPrime']);

// Real subjectvar PrimeChecker = function () { // implements IPrimeChecker};

PrimeChecker.prototype.isPrime = function (num) {for (var i = 2; i <= Math.sqrt(num); i++) {

if (num % i == 0)return false;

}return true;

};

25

Example: Proxy

// Proxyvar PrimeCheckerProxy = function () { // implements IPrimeChecker

this._primeChecker = new PrimeChecker();this._numbers = {};

};

PrimeCheckerProxy.prototype.isPrime = function (num) { if (this._numbers[num] === undefined) { // be careful not to compare to false

this._numbers[num] = this._primeChecker.isPrime(num);}

return this._numbers[num];};

Example: Using the Proxyvar primeChecker = new PrimeCheckerProxy();

$(document).ready(function () {$('#btnCheckPrime').click(function () {

var num = parseInt($('#txtNum').val());

var start = new Date().getTime();var isPrime = primeChecker.isPrime(num);var end = new Date().getTime();var timeElapsed = end - start;

if (isPrime)$('#lblResult').html('This is a prime number');

else$('#lblResult').html('This is not a prime number');

$('#lblTime').html("Time to compute: " + timeElapsed + " milliseconds");});

});

26

Observer PatternDefine a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.

+Attach(in Observer)+Detach(in Observer)+Notify()

Subject

+Update()

Observer

+GetState()-subjectStateConcreteSubject

+Update()-observerStateConcreteObserver

foreach o in observerso.Update()

return subjectState observerState =subject.GetState()

Exercise

• Implement the Observer Design Pattern using the techniques learned in class• The Subject will be a mail server that will broadcast incoming messages to registered users (the observers).• The Observer will be a mail client that can send and receive messages from the mail server.

27

JavaScript Best Practices and Performance Tips

• Efficient Java Script• Core Java Script Performance Tips• DOM Access• JavaScript Profilier

Efficient JavaScript• As web pages become more like applications, the

performance of scripts is having a bigger effect. • With more and more applications being developed

using Web technologies, improving the performance of scripts is becoming increasingly important.

• With a desktop application, a compiler is normally used to convert the source into the final binary.

• The compiler can take its time, and optimize as much as possible for good performance of the final application. Web applications do not have that luxury.

28

Efficient JavaScript• The browser has to do the interpretation and

compilation each time it retrieves a script, and yet the final application has to run as smoothly as a desktop application, and load quickly as well.

• Browsers are fairly good at achieving this. However, browsers do have their limits, and that is where the Web developer has to take over.

Caching Your Objects

• One of the best kept secrets to boosting script performance is to cache your objects.

• Often times, your script will repeatedly access a certain object, as in the following demonstration:for (var i = 0; i < document.images.length; i++) {

document.images[i].src = "blank.gif";}

29

Caching Your Objects

• Caching your object means storing a repeatedly access object inside a user defined variable, and using that variable instead in subsequent references to the object.

• The performance improvement can be significant.

Caching Your Objects

• Here's a modified version of the initial script using object caching:var docImages = document.images;for (var i = 0; i < docImages.length; i++) {

docImages[i].src = "blank.gif";}

30

Avoid for-in loops• The for-in loop has its place, but is often misused, when a

normal for loop would be more appropriate. • The for-in loop requires the script engine to build a list of all

the enumerable properties, and check for duplicates in that list, before it can start the enumeration.

• In many cases, a simple for loop could be used to step through those properties, especially if they are named using sequential numbers, such as with an array, or an object that is given properties to make it appear to be an array (for instance, a NodeList object created by DOM).

Avoid for-in loops

var arr = [1, 2, 3, 4, 5];

var sum = 0;for (var i in arr) {

sum += arr[i];}

31

Avoid for-in loops

var sum = 0;var length = arr.length;for (var i = 0; i < length; i++) {

sum += arr[i];}

• A for loop would be more efficient:

Avoid using eval• Each time eval is called on a string representing source code,

the script engine must start the machinery that converts the source code to executable code.

• This is usually expensive for performance - easily a hundred times more expensive than a simple function call, for example.

• Since the code is interpreted in the context of the call to eval this means that the compiler cannot optimize the surrounding context, and the browser is left to interpret much of the surrounding code at runtime. This adds an additional performance impact.

32

Rewrite that eval

function getProperty(propName) {var propValue;eval('propValue = myobject.' + propName);return propValue;

}

Rewrite that eval

function getProperty(propName) {return myobject[propName];

}

• The code that does not use eval performs around 95% faster than the original in Firefox, Internet Explorer, and Opera, and around 85% faster in Safari.

33

Avoid using global variables• It can be tempting to create variables in the global

scope, simply because that is easy to do. • However, there are several reasons why this can

make scripts run more slowly.• If code inside a function or another scope

references that variable, the script engine has to step up through each scope in turn until it reaches the global scope. A variable in the local scope will be found more quickly.

Avoid using global variables

• Variables in the global scope also persist through the life of the script.

• In the local scope, they are destroyed when the local scope is lost. The memory they use can then be freed by the garbage collector.

34

Avoid using global variables

var i, str = "";function testfunction() {

for (i = 0; i < 20; i++) {str += i;

}alert(str);

}testfunction();

Without global variablesfunction testfunction() {

var str = "";for (var i = 0; i < 20; i++) {

str += i;}alert(str);

}testfunction();

• This alternative version performs measurably faster. In latest versions of Internet Explorer, Firefox, Opera and Safari, execution is about 30% faster than the original.

35

Use Closures Sparingly• Closures are a very powerful and useful aspect

of Javascript, but they come with their own performance drawbacks.

• In a closure, the script engine to find the value associated with a variable, the script engine has to search up the scope chain

• Also closures keep the local variables in memory

Use Closures Sparingly• Bad closures example

function a(x) {function b(y) {

return (function (z) {return x + y + z;

})(y + y);}return b(x + 3);

}alert(a(1));

36

Use Closures Sparingly• Better:function a(x) {

var y = x + 3;var z = y + y;return x + y + z;

}

alert(a(1));

Beware of Implicit Object Conversion• Literals, such as strings, numbers, and boolean

values, have two representations within ECMAScript.

• Each of them can be created as either a value or an object.� For example, a string value is created simply by

saying var str = 'some content'; � an equivalent string object is created by saying

var str = new String('some content');.

37

Beware of Implicit Object Conversion

• Any properties and methods are defined on the string object, not the string value.

• When you reference a property or method of a string value, the ECMAScript engine must implicitly create a new string object with the same value as your string, before running the method.

Beware of Implicit Object Conversion• The following example creates 21 new string

objects, once for each time the length property is accessed, and once each time the charAt method is called:

var str = '0123456789';for (var i = 0; i < str.length; i++) {

alert(str.charAt(i));}

38

Beware of Implicit Object Conversion• This equivalent example creates just a single

object, and will perform better as a result:

• If your code calls methods of literal values very often, you should consider converting them into objects instead, as in the previous example.

var str = new String('0123456789');for (var i = 0; i < str.length; i++) {

alert(str.charAt(i));}

DOM Access• There are three main things that can cause DOM to

perform slowly. 1. When a script triggers too many reflows or repaints. 2. When a script takes a slow approach to locating a

desired node in the DOM tree.3. When a script performs some extensive DOM

manipulation, such as building a new tree from some retrieved data.

39

Repaint and reflow• Repaint - also known as redraw - is what happens whenever

something is made visible when it was not previously visible, or vice versa, without altering the layout of the document.

• An example would be when adding an outline to an element, changing the background color, or changing the visibility style.

• Repaint is expensive in terms of performance, as it requires the engine to search through all elements to determine what is visible, and what should be displayed.

Repaint and reflow• A reflow is a more significant change. • This will happen whenever the DOM tree is manipulated,

whenever a style is changed that affects the layout, whenever the className property of an element is changed, or whenever the browser window size is changed.

• The engine must then reflow the relevant element, its children, the elements that appear after it in the DOM to take the new layout of the element into account.

• Ancestor elements will also reflow, to account for the changes in size of their children.

• Finally, everything is repainted.

40

Repaint and reflow• Reflows are a fact of Web development, and to keep scripts

running fast, they should be kept to a minimum while still having the same overall effect.

• Browsers may choose to wait until the end of a script thread or until enough changes have been made before reflowing to show the changes.

• Some elements have significantly slower reflows than others. � Reflowing an element with table display, can take as much as three

times as long as reflowing an equivalent element with block display.

Minimal reflow• Normal reflows may affect the whole document. • The more of the document that is reflowed, the longer the reflow

will take. • Elements that are positioned absolutely or fixed, do not affect the

layout of the main document, so if they reflow, they are the only thing that reflows.

• The document behind them will need to repaint to allow for any changes, but this is much less of a problem than an entire reflow.

• So if an animation does not need to be applied to the whole document, it is better if it can be applied only to a positioned element.

41

Document Tree Modification• Document tree modification will trigger reflow. • Adding new elements to the DOM, changing the value of text

nodes, or changing various attributes will all be enough to cause a reflow.

• Making several changes one after the other, may trigger more than one reflow

• In general it is best to make multiple changes in a non-displayed DOM tree fragment.

• The changes can then be made to the live document's DOM in one single operation

Document Tree Modification

var textlist = ['paragraph 1', 'paragraph 2', 'paragraph 3'];

var docFragm = document.createDocumentFragment();var elem, contents;for (var i = 0; i < textlist.length; i++) {

elem = document.createElement('p');contents = document.createTextNode(textlist[i]);elem.appendChild(contents);docFragm.appendChild(elem);

}document.body.appendChild(docFragm);

42

Modifying an Invisible Element• When an element has its display style set to none, it will not

need to repaint, even if its contents are changed, since it is not being displayed. This can be used as an advantage.

• If several changes need to be made to an element or its contents, and it is not possible to combine these changes into a single repaint, the element can be set to display:none, the changes can be made, then the element can be set back to its normal display.

• This will trigger two extra reflows, once when the element is hidden, and once when it is made to appear again, but the overall effect can be much faster.

Modifying an Invisible Element

var elem = document.getElementById('animation');elem.style.display = 'none';elem.appendChild(newNodes);elem.style.width = '10px';// other changes...elem.style.display = 'block';

43

Change CSS classes, not styles

• Just like with DOM tree modifications, it is possible to make several style related changes at the same time, in order to minimize the number of repaints or reflows.

• The common approach is setting of styles one at a time:

• That approach could mean multiple reflows and repaints.

var elem = document.getElementById('myelement');elem.style.background = '#333';elem.style.color = '#fff';elem.style.border = '2px solid #00f';

Change CSS classes, not styles• If the element itself needs to adopt several styles, whose

values are all known in advance, the class of the element can be changed.

• It will then take on all the new styles defined for that class:<style>

div.highlight{

background: #333;color: #fff;border: 2px solid #00f;

}</style>

document.getElementById('myelement').className = 'highlight';

44

Change CSS classes, not styles• The second approach is to define a new style attribute for the

element, instead of assigning styles one by one.• Most often this is suited to dynamic changes such as

animations, where the new styles cannot be known in advance.

• This is done using either the cssText property of the style object, or by using setAttribute. IE does not allow the second version, and needs the first.

• Or you can use the jQuery css() function

Change CSS classes, not styles

$('#myelement').css({ 'background-color': '#333','color': '#fff','border': '2px solid #00f'

});

45

Minimize DOM Access

• Some values returned by DOM cannot be cached, and will be reassessed each time they are called.

• An example is the getElementById method. The following is an example of wasteful code:

document.getElementById('test').property1 = 'value1';document.getElementById('test').property2 = 'value2';document.getElementById('test').property3 = 'value3';document.getElementById('test').property4 = 'value4';

Minimize DOM Access

• The following code makes one request then stores it:

• For the first request, the speed is about the same, or very slightly slower while performing the assignment.

• However, each subsequent time the cached value is used, the command runs between five and ten times as fast in most current browsers

F th fi t t th d i b t th

g q

h f h d b h

var elem = document.getElementById('test');elem.property1 = 'value1';elem.property2 = 'value2';elem.property3 = 'value3';elem.property4 = 'value4‘;

46

Shrink Your JavaScript Files

• Minification is the practice of removing unnecessary characters from code to reduce its size, thus improving load times.

• Online JavaScript Compression Tool• http://jscompress.com/

• Uglify JS: http://github.com/mishoo/UglifyJS• Used by the jQuery project

Access JavaScript Files through CDNs• A content delivery network (CDN) is a large distributed system

of servers deployed in multiple data centers in the Internet. • The goal of a CDN is to serve content to end-users with high

availability and high performance.• Accessing JavaScript files through CDNs has several benefits:

� You offload your own servers.� You increase the odds that the file is cached, since other sites

will be linking to the same file.� A CDN will probably deliver the file faster than you can.

47

Access JavaScript Files through CDNs

• Accessing jQuery through CDN:

<script src="http://code.jquery.com/jquery-1.8.0.min.js"></script>

JavaScript Profiling

• The Profiles panel in Chrome Developer Tools lets you profile the execution time and memory usage of a web app or page.

• The Profiles panel includes two profilers: a CPU profiler and a Heap profiler.

• These help you to understand where resources are being spent, and so help you to optimize your code:

48

JavaScript Profiling

DemoJavaScript Profiling

49

Structuring Web Applications

• Focus is moving from server to client• Writing web applications, not web sites• We want desktop-like application• State need to be handled on the client• jQuery is not enough• Client side code requires design and modeling

Problems We Face• There is no golden path• Few conventions and standards• Countless interpretations of traditional patterns like

MVC• Plenty of options – Backbone, Spine, Knockout,

JavascriptMVC, Dojo, Ext JS, GWT, and more • If you choose one technology track, you’re trapped

50

Backbone

• A simple small library (6.3KB for the production version) to separate business and user interface logic

• Growing popularity• Actively developed• Free and open source• Downloadable from http://backbonejs.org

Backbone

51

Backbone

• Real-world projects that use backbone:• Walmart Mobile• Groupon Now!• Pandora• WordPress.com• USA Today

Backbone Architecture

• Gives structure to web applications• Supports models with key-value binding• Supports views with declarative event handling• Connects it all using a Router

52

Backbone Architecture

Backbone Lifecycle

• You represent data as Models‒ Supports create/validate/destroy/save to server

• Whenever a UI action changes an attribute of the model‒ The model triggers “change” event‒ All views are notified‒ Views re-render themselves with the new

information

53

Backbone Lifecycle• In a Backbone app, you don't have to write the

glue code that looks into the DOM to find an element with a specific id, and update the HTML manually — when the model changes, the views simply update themselves.

Getting Started

• Download Backbone• Download dependencies

• Underscore.js• Underscore is a JavaScript library which provides utility

functions for common JavaScript tasks

• jQuery/Zepto• Zepto is mainly used in mobile apps ad lightweight

replacement to jQuery

54

Backbone Models

• A model is a collection of key-value pairs• Inherits from the general Backbone.Model type• Changes of its attributes will fire change events• Models may be retrieved from and saved to a

data storage

Backbone Models

// Product Modelvar Product = Backbone.Model.extend({

initialize: function () {// Ensure that each product has a priceif (!this.get("price")) {

this.set("price", 0);}

},log: function () {

console.log("Name: " + this.get("name"));console.log("Price: " + this.get("price"));

}});

55

Create an Instance

• When creating an instance of a model, you can pass in the initial values of the attributes, which will be set on the model.

• If you define an initialize function, it will be invoked when the model is created.

• Clients cannot access the model’s fields directly

Create an Instance

var product = new Product({name: "Apple",price: 3.5

});

alert(product.get("name"));product.log();

56

Inheritance• Custom model can inherit from another custom model• No support for super keyword �

var Book = Product.extend({initialize: function () {

Product.prototype.initialize.call(this);},log: function () {

Product.prototype.log.call(this);console.log("Author: " + this.get("author"));console.log("ISBN: " + this.get("ISBN"));

}});

Events

• Use on() to register to an event– First argument: event name– Second argument: callback function

• Inside the callback this references the model• Use trigger() to raise the event

– First argument: event name– Second argument: user-defined event arguments

• Use off() to remove a previously-bound callback function from an object

57

Events

var Product = Backbone.Model.extend({saveToServer: function () {

this.trigger("savedToServer", { when: new Date() });}

});

product.on("savedToServer", function (args) {console.log(this.get("name") + " saved at: " + args.when);

});

product.saveToServer();

Change Events

• Whenever an attribute of the model is changed, the event "change:[attribute]" will be automatically triggeredy ggy gg

product.on("change:price", function (model, value) {console.log(this.get("name") + " price changed to: " +

value);});

product.set("price", 5.2);

58

Model Events

• Other model events:– change (model, options) — when a model's attributes have changed.– change:[attribute] (model, value, options) — when a specific attribute

has been updated.– destroy (model, collection, options) — when a model is destroyed.– sync (model, resp, options) — when a model has been successfully

synced with the server.– error (model, collection) — when a model's validation fails, or

a save call fails on the server.– all — this special event fires for any triggered event, passing the event

name as the first argument.

Model Identity

• The identity is exposed through an attribute named id• After creating a model the id is undefined• Only after saving the model to the server, the id is

populated with identity returned from the server• Can use the isNew() method to determine if the model

was saved yet to the server• Backbone supports a temporary id named cid

59

Model Identity// Model Identityconsole.log("id: " + product.id);console.log("cid: " + product.cid);

product.save({}, {success: function () {

console.log("id: " + product.id);console.log("cid: " + product.cid);

},error: function () {

console.log("error");}

});id: undefinedcid: c1id: 3cid: c1

Model Validation

• Backbone detects existence of a validate() method• Is called internally by

– set()– save()– isValid()

• Should return false to indicate no error• Can return any object to represent validation errors

60

Model Validationvar Product = Backbone.Model.extend({

validate: function (attrs) {console.log("validate");if (attrs.price < 0) {

return "price must be positive or equal to zero";}return false;

} });

Useful Model Methods

• has – determine if an attribute was previously set• unset – remove an attribute• clear – remove all attributes• escape – same as get but returns HTML escaped string• attributes – internal object which holds all attributes• toJSON – returns a copy of the model attributes for

JSON stringification

61

Collections

• Collections are ordered sets of models• Supports change event notifications

– You can bind "change" events to be notified when any model in the collection has been modified, listen for "add" and "remove" events

• Has a suite of Underscore.js methods• Supports toJSON()

Collections// Collectionsvar Products = Backbone.Collection.extend({

model: Product,url: "/api/Products",comparator: "price"

});

var products = new Products();products.add(new Product({ name: "Bamba", price: 4.5 }));products.add(new Product({ name: "Bisli", price: 5.2 }));

products.each(function (product) {product.log();

});

62

Useful Collection’s Methods

• at – get a model from a collection, specified by index• get – get a model by id• add – add a model to the collection• remove – remove a model from the collection• reset – reset to a specified list• where – return an array of all the models in a collection

that match the passed attributes.• sync – persist the state of the collection to the server. Can

be overridden for custom behavior.

Collection Events

• add (model, collection, options) — when a model is added to a collection.

• remove (model, collection, options) — when a model is removed from a collection.

• reset (collection, options) — when the collection's entire contents have been replaced.

• sort (collection, options) — when the collection has been re-sorted.

63

The View

• Backbone views are almost more convention than they are code — they don't determine anything about your HTML or CSS for you, and can be used with any JavaScript templating library.

• The general idea is to organize your interface into logical views, backed by models, each of which can be updated independently when the model changes, without having to redraw the page.

The View

• Instead of digging into a JSON object, looking up an element in the DOM, and updating the HTML by hand, you can bind the view’s render function to the model's "change" event, and now everywhere that model data is displayed in the UI, it is always immediately up to date.

64

The View

• We define view type just as a model type• A view is mapped to exactly one DOM element• Has a model attribute• Has a render() method which is responsible for

updating the DOM element

Define a View

• Get started with views by creating a custom view class.

• You'll want to override the render function, specify your declarative events, and perhaps the tagName, className, or id of the View's root element.

65

Define a View// Product Viewvar ProductView = Backbone.View.extend({

tagName: "div",id: "productView“, attributes: { "data-value": 1 },events: { "click .btnMakeDiscount": "makeDiscount" },

// Grab the HTML out of our template tag and pre-compile it.template: _.template($('#product-template').html()),

render: function () {this.$el.html(this.template(this.model.toJSON())); return this;

},

makeDiscount: function () {this.model.set("price", this.model.get("price") * 0.9);alert("Price was changed");

}});

Useful View’s Members

• el – a reference to the DOM element• $el – a cached jQuery wrapper of the DOM element. A

handy reference instead of re-wrapping the DOM element all the time.

• $ – shortcut for jQuery $ but with the correct context– view.$(selector) is equivalent to view.$el.find(selector)

• attributes – a hash of attributes that will be set as HTML DOM element attributes on the view's el

• remove() – shortcut for $el.remove()

66

View Render

• The default implementation of render is a no-op. Override this function with your code that renders the view template from model data, and updates this.el with the new HTML.

• Because Underscore.js is already on the page, _.template is available, and is an excellent choice if you prefer simple interpolated-JavaScript style templates.

• A good convention is to return this at the end of render to enable chained calls.

Define a Template

<!-- Templates --><script type="text/template" id="product-template">

<div class="productView">Name: <%- name %> <br/>Price: <%- price.toFixed(2) %><br/> <button class="btnMakeDiscount">Make Discount</button>

</div> </script>

67

Instantiate the View

• After creating an instance of the view, you need to insert its DOM element into the document

• Or, assuming there is an element with id ‘p2’hh idd ‘‘‘ 2’’’O i th i l t itO i hh i ll i

var view = new ProductView({ model: product });$('body').append(view.render().el);

var view2 = new ProductView({ model: product, el: "#p2" });view2.render();

Update a View when Model Changes

var ProductView = Backbone.View.extend({

initialize: function () {this.listenTo(this.model, 'change', this.render);

},

});

68

Final Result

Routing

• Backbone.Router provides methods for routing client-side pages, and connecting them to actions and events

• When the browser URL changes, a function is triggered• Backbone parses the URL and delegates to the correct

route handler• Allows you to change the URL without submitting a

request to the server– Allows for bookmarking– Use sparsely

69

Routingvar MainRouter = Backbone.Router.extend({

routes: {"": "defaultRoute","product/:type": "product"

},defaultRoute: function () {

console.log("Default route");var products = new Products();var productsView = new ProductsView({ collection: products });$('#body').html(productsView.render().el);

},product: function (type) {

var productFactory = getProductFactoryByTypeName(type);var product = productFactory.create();var view = createViewForModel(product);$('#body').html(view.render().el);

}});

Routing

• Defining a route type does not affect application• You need to instantiate a route object and initialize

Backbone routing mechanism

• You can manually navigate to a route

gggggvar router = new MainRouter();Backbone.history.start({ pushState: true });

router.navigate("product/Apple", { trigger: true });

70

Connecting to a Server

• Backbone uses RESTful web requests to synchornize data

• A model type can define the URL to be used for server synchronization

• Usually the URL is taken from the parent collectionvar Products = Backbone.Collection.extend({

model: Product,url: "/api/Products",

});

Fetch a Model

• Call the fetch method• A GET request with the relevant ID is sent• Returned JSON is set back to the model

– Overwriting existing statevar prod = new Product({ id: 1 });prod.fetch({

success: function () {alert(this.get("name") + " was fetched from server");

},});

http://localhost:20076/api/Products/1

71

Fetch a Collection

• A GET request is sent• Returned JSON contains an array of models• Backbone creates a Model object for each record

var products = new Products();products.fetch( {

success: function() {products.each(function(product) {

product.log();});

}});

Save a Model

• In case of a new model– A POST request is sent– Server should return a JSON with the real ID– Backbone updates the model state and id– isNew now returns falsevar prod = new Product({ name: 'Cookie', price: 3.4 });prod.save( {}, {

success: function() {},error: function() {}

});

POST http://localhost:20076/api/Products

72

Save a Model

• In case of existing model– A PUT request is sent– Requested URL contains model IDprod.save( {}, {

success: function() {},error: function() {}

});

PUT http://localhost:20076/api/Products/12

Delete a Model

• Ignore request in case of isNew = true– Model is removed from the collection

• A DELETE request is sent• Requested URL contains model ID• Consider setting wait = true

prod.destroy({}, {success: function () { },error: function () { },wait: true

});

DELETE http://localhost:20076/api/Products/12

73

ToDo List Example

Backbone - Summary

• A way to construct web application• Can be easily integrated into existing applications• Quite thin• Consider using client-side templates for rendering

views

74

75