jquery design patterns · 2016. 5. 12. · table of contents jquery design patterns credits about...

358

Upload: others

Post on 04-Sep-2020

2 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 2: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 3: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

jQueryDesignPatterns

Page 4: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

TableofContents

jQueryDesignPatterns

Credits

AbouttheAuthor

AbouttheReviewer

www.PacktPub.com

eBooks,discountoffers,andmore

Whysubscribe?

Preface

Whatthisbookcovers

Whatyouneedforthisbook

Whothisbookisfor

Conventions

Readerfeedback

Customersupport

Downloadingtheexamplecode

Errata

Piracy

Questions

1.ARefresheronjQueryandtheCompositePattern

jQueryandDOMscripting

ManipulatingtheDOMusingjQuery

MethodChainingandFluentInterfaces

TheCompositePattern

HowtheCompositePatternisusedbyjQuery

ComparingthebenefitsovertheplainDOMAPI

UsingtheCompositePatterntodevelopapplications

Asampleusecase

TheCompositeCollectionImplementation

Anexampleexecution

Page 5: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

Alternativeimplementations

TheIteratorPattern

HowtheIteratorPatternisusedbyjQuery

HowitpairswiththeCompositePattern

Wherecanitbeused

Summary

2.TheObserverPattern

IntroducingtheObserverPattern

HowitisusedbyjQuery

ThejQueryonmethod

Thedocument-readyobserver

Demonstrateasampleusecase

Howitiscomparedwitheventattributes

Avoidmemoryleaks

IntroducingtheDelegatedEventObserverPattern

Howitsimplifiesourcode

Comparethememoryusagebenefits

Summary

3.ThePublish/SubscribePattern

IntroducingthePublish/SubscribePattern

HowitdiffersfromtheObserverPattern

HowitisadoptedbyjQuery

CustomeventsinjQuery

ImplementingaPub/Subschemeusingcustomevents

Demonstratingasampleusecase

UsingPub/Subonthedashboardexample

Extendingtheimplementation

Usinganyobjectasabroker

Usingcustomeventnamespacing

Summary

4.DivideandConquerwiththeModulePattern

Page 6: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

ModulesandNamespaces

Encapsulatinginternalpartsofanimplementation

AvoidingglobalvariableswithNamespaces

Thebenefitsofthesepatterns

Thewideacceptance

TheObjectLiteralPattern

TheModulePattern

TheIIFEbuildingblock

ThesimpleIIFEModulePattern

HowitisusedbyjQuery

TheNamespaceParameterModulevariant

TheIIFE-containedModulevariant

TheRevealingModulePattern

UsingES5StrictMode

IntroducingES6Modules

UsingModulesinjQueryapplications

Themaindashboardmodule

Thecategoriesmodule

TheinformationBoxmodule

Thecountermodule

Overviewoftheimplementation

Summary

5.TheFacadePattern

IntroducingtheFacadePattern

Thebenefitsofthispattern

HowitisadoptedbyjQuery

ThejQueryDOMTraversalAPI

ThepropertyaccessandmanipulationAPI

UsingFacadesinourapplications

Summary

6.TheBuilderandFactoryPatterns

Page 7: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

IntroducingtheFactoryPattern

HowitisadoptedbyjQuery

UsingFactoriesinourapplications

IntroducingtheBuilderPattern

HowitisadoptedbyjQuery’sAPI

HowitisusedbyjQueryinternally

Howtouseitinourapplications

Summary

7.AsynchronousControlFlowPatterns

Programmingwithcallbacks

UsingsimplecallbacksinJavaScript

Settingcallbacksasobjectproperties

UsingcallbacksinjQueryapplications

Writingmethodsthatacceptcallbacks

Orchestratingcallbacks

Queuinginorderexecution

AvoidingtheCallbackHellanti-pattern

Runningconcurrently

IntroducingtheconceptofPromises

UsingPromises

UsingthejQueryPromiseAPI

UsingPromises/A+

ComparingjQueryandA+Promises

Advancedconcepts

ChainingPromises

Handlingthrownerrors

JoiningPromises

HowjQueryusesPromises

TransformingPromisestoothertypes

TransformingtoPromises/A+

TransformingtojQueryPromises

Page 8: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

SummarizingthebenefitsofPromises

Summary

8.MockObjectPattern

IntroducingtheMockObjectPattern

UsingMockObjectsinjQueryapplications

Definingtheactualservicerequirements

ImplementingaMockService

UsingtheMockService

Summary

9.Client-sideTemplating

IntroducingUnderscore.js

UsingUnderscore.jstemplatesinourapplications

SeparatingHTMLtemplatesfromJavaScriptcode

IntroducingHandlebars.js

UsingHandlebars.jsinourapplications

SeparatingHTMLtemplatesfromJavaScriptcode

Pre-compilingtemplates

RetrievingHTMLtemplatesasynchronously

Adoptingitinanexistingimplementation

Moderationisbestinallthings

Summary

10.PluginandWidgetDevelopmentPatterns

IntroducingjQueryPlugins

FollowingjQueryprinciples

WorkingonCompositeCollectionObjects

Allowingfurtherchaining

Workingwith$.noConflict()

WrappingwithanIIFE

Creatingreusableplugins

Acceptingconfigurationparameters

WritingstatefuljQueryplugins

Page 9: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

ImplementingastatefuljQueryPlugin

Destroyingaplugininstance

Implementinggetterandsettermethods

UsingourplugininourDashboardapplication

UsingthejQueryPluginBoilerplate

Addingmethodstoyourplugin

Choosinganame

Summary

11.OptimizationPatterns

Placingscriptsneartheendofthepage

Bundlingandminifyingresources

UsingIIFEparameters

UsingCDNs

UsingJSDelivrAPI

OptimizingcommonJavaScriptcode

Writingbetterforloops

WritingperformantCSSselectors

WritingefficientjQuerycode

MinimizingDOMtraversals

CachingjQueryobjects

Scopingelementtraversals

ChainingjQuerymethods

Don’toverdoit

ImprovingDOMmanipulations

CreatingDOMelements

Stylingandanimating

Manipulatingdetachedelements

IntroducingtheFlyweightPattern

UsingDelegateObservers

Using$.noop()

Usingthe$.singleplugin

Page 10: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

LazyLoadingModules

Summary

Index

Page 11: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 12: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

jQueryDesignPatterns

Page 13: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 14: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

jQueryDesignPatternsCopyright©2016PacktPublishing

Allrightsreserved.Nopartofthisbookmaybereproduced,storedinaretrievalsystem,ortransmittedinanyformorbyanymeans,withoutthepriorwrittenpermissionofthepublisher,exceptinthecaseofbriefquotationsembeddedincriticalarticlesorreviews.

Everyefforthasbeenmadeinthepreparationofthisbooktoensuretheaccuracyoftheinformationpresented.However,theinformationcontainedinthisbookissoldwithoutwarranty,eitherexpressorimplied.Neithertheauthor,norPacktPublishing,anditsdealersanddistributorswillbeheldliableforanydamagescausedorallegedtobecauseddirectlyorindirectlybythisbook.

PacktPublishinghasendeavoredtoprovidetrademarkinformationaboutallofthecompaniesandproductsmentionedinthisbookbytheappropriateuseofcapitals.However,PacktPublishingcannotguaranteetheaccuracyofthisinformation.

Firstpublished:February2016

Productionreference:1230216

PublishedbyPacktPublishingLtd.

LiveryPlace

35LiveryStreet

BirminghamB32PB,UK.

ISBN978-1-78588-868-7

www.packtpub.com

Page 15: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 16: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

CreditsAuthor

ThodorisGreasidis

Reviewer

AamirAfridi

CommissioningEditor

NeilAlexander

AcquisitionEditor

AaronLazar

ContentDevelopmentEditor

RiddhiTuljapurkar

TechnicalEditor

PramodKumavat

CopyEditors

TrishyaHazare

KevinMcGowan

ProjectCoordinator

SanchitaMandal

Proofreader

SafisEditing

Indexer

RekhaNair

Graphics

AbhinashSahu

ProductionCoordinator

ShantanuN.Zagade

CoverWork

ShantanuN.Zagade

Page 17: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 18: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

AbouttheAuthorThodorisGreasidisisaseniorwebengineerfromGreece.HegraduatedwithhonorsfromtheUniversityofThessaly,holdsapolytechnicdiplomaincomputer,networking,andcommunicationsengineering,andamaster’sdegreeincomputerscience.Heisafull-stackdeveloper,responsibleforimplementinglarge-scalewebapplicationswithintuitiveinterfacesandhigh-availabilitywebservices.

ThodorisispartoftheAngular-UIteamandhasmademanyopensourcecontributions,withaspecialinterestinMozillaprojects.HeisalsoanactivememberoftheAthensAngularJSMeetupandatechnicalreviewerofMasteringjQueryUI,PacktPublishing.

HeisaJavaScriptenthusiastandlovesbitwiseoperations.HisinterestsalsoincludeNodeJS,Python,projectscaffolding,automation,andartificialintelligence,especiallymulti-agentsystems.

Abigthankstoeveryonewhosupportedmeandshowedunderstandingformylimitedfreetimewhilewritingthisbook.

Page 19: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 20: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

AbouttheReviewerAamirAfridihasbeenpassionateabouttheInternetandwebdevelopmentsince2002.Heholdsamaster’sdegreeine-commerce.Overtheyearsthathavefollowed,hehasworkedforvariouscompaniesandprovidedfrontendengineering,includingmobilewebappsandarchitectureserviceswithafocusonsemanticHTML,CSS,andJavaScript/jQueryandanythingelsehecangethishandson.HehascontributedtoJavaScriptbooksasatechnicalreviewer.Thesedays,heisexploringthemicroservicesarchitecturewithNodeJS,MongoDB,andReactJSatwww.tes.com.Heblogsonhttp://aamirafridi.com.

Page 21: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 22: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

www.PacktPub.com

Page 23: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

eBooks,discountoffers,andmoreDidyouknowthatPacktofferseBookversionsofeverybookpublished,withPDFandePubfilesavailable?YoucanupgradetotheeBookversionatwww.PacktPub.comandasaprintbookcustomer,youareentitledtoadiscountontheeBookcopy.Getintouchwithusat<[email protected]>formoredetails.

Atwww.PacktPub.com,youcanalsoreadacollectionoffreetechnicalarticles,signupforarangeoffreenewslettersandreceiveexclusivediscountsandoffersonPacktbooksandeBooks.

https://www2.packtpub.com/books/subscription/packtlib

DoyouneedinstantsolutionstoyourITquestions?PacktLibisPackt’sonlinedigitalbooklibrary.Here,youcansearch,access,andreadPackt’sentirelibraryofbooks.

Page 24: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

Whysubscribe?FullysearchableacrosseverybookpublishedbyPacktCopyandpaste,print,andbookmarkcontentOndemandandaccessibleviaawebbrowser

Page 25: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 26: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

PrefaceSinceitsintroductionin2006,thejQuerylibraryhasmadeDOMtraversalsandmanipulationsmucheasier.ThishasresultedintheappearanceofWebpageswithincreasinglycomplexuserinteractions,thuscontributingtothematuringofWebasaplatformcapableofsupportinglargeapplicationimplementations.

ThisbookpresentsaseriesofbestpracticesthatmaketheimplementationofWebapplicationsmoreefficient.Moreover,wewillanalyzethemostimportantDesignPatternsthatComputerSciencehastooffer,whichcanbeappliedtoWebdevelopment.Inthisway,wewilllearnhowtoutilizetechniquesthatarethoroughlyusedandtestedinotherfieldsofprogramming,whichwereinitiallycreatedasgenericmethodstomodelsolutionsofcomplexproblems.

InjQueryDesignPatterns,wewillanalyzehowvariousDesignPatternsareutilizedintheimplementationofjQueryandhowtheycanbeusedtoimprovetheorganizationofourimplementations.ByadoptingtheDesignPatternsdemonstratedinthisbook,youwillbeabletocreatebetterorganizedimplementationsthatresolvelargeproblemcategoriesfaster.Moreover,whenusedbyadeveloperteam,theycanimprovethecommunicationbetweenthemandleadtohomogenousimplementation,whereeverypartofthecodeiseasilyunderstoodbyothers.

Page 27: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

WhatthisbookcoversChapter1,ARefresheronjQueryandtheCompositePattern,willteachthereaderhowtowritethecodeusingtheCompositePatternandmethodchaining(FluentInterface)byanalyzinghowtheyareusedfortheimplementationofjQueryitself.ItalsodemonstratestheIteratorPatternthatnicelypairswiththeCompositeCollectionobjectsthatjQueryreturns.

Chapter2,TheObserverPattern,willteachyouhowtorespondtouseractionsusingtheObserverPattern.ItalsodemonstrateshowtouseEventDelegationasawaytoreducethememoryconsumptionandcomplexityofthecodethathandlesdynamicallyinjectedpageelements.Finally,itwillteachyouhowtoemitandlistenforCustomEventsinordertoachievegreaterflexibilityandcodedecoupling.

Chapter3,ThePublish/SubscribePattern,willteachyouhowtoutilizethePub/SubPatterntocreateacentralpointtoemitandreceiveapplication-levelevents,asawaytodecoupleyourcodeandbusinesslogicfromtheHTMLthatisusedforpresentation.

Chapter4,DivideandConquerwiththeModulePattern,demonstratesandcomparessomeofthemostcommonlyusedModulePatternsintheindustry.ItwillteachyouhowtostructureyourapplicationinsmallindependentModulesusingNamespacing,leadingtoexpandableimplementationsthatfollowtheSeparationofConcernsprinciple.

Chapter5,TheFacadePattern,willteachyouhowtousetheFacadePatterntowrapcomplexAPIsintosimpleronesthatareabettermatchfortheneedsofyourapplication.Italsodemonstrateshowtochangepartsofyourapplication,whilekeepingthesamemodule-levelAPIsandavoidaffectingtherestofyourimplementation.

Chapter6,TheBuilderandFactoryPatterns,explainstheconceptsofandthedifferencesbetweentheBuilderandFactoryPatterns.Itwillteachyouhowandwhentouseeachofthem,inordertoimprovetheclarityofyourcodebyabstractingthegenerationofcomplexresultsintoseparatededicatedmethods.

Chapter7,AsynchronousControlFlowPatterns,willexplainhowjQuery’sDeferredandPromiseAPIsworkandcomparethemwiththeclassicalCallbacksPattern.YouwilllearnhowtousePromisestocontrolthetheexecutionofasynchronousprocedurestoruneitherinanorderorparalleltoeachother.

Chapter8,MockObjectPattern,teachesyouhowtocreateanduseMockObjectsandServicesasawaytoeasethedevelopmentofyourapplicationandgetasenseofitsfunctionality,longbeforeallitspartsarecompleted.

Chapter9,Client-sideTemplating,demonstrateshowtousetheUnderscore.jsandHandlebars.jstemplatinglibrariesasabetterandfasterwaytocreatecomplexHTMLstructureswithJavaScript.Throughthischapter,youwillgetanoverviewoftheirconventions,evaluatetheirfeatures,andfindtheonethatbestmatchesyourtaste.

Chapter10,PluginandWidgetDevelopmentPatterns,introducesthebasicconceptsandconventionsofjQueryPlugindevelopmentandanalyzesthemostcommonlyuseddesign

Page 28: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

patterns,sothatyouwillbeabletoidentifyandusethebestmatchforanyusecase.

Chapter11,OptimizationPatterns,guidesyouwiththebesttipstocreateahighlyefficientandrobustimplementation.Youwillbeabletousethischapterasachecklistofbestpracticesthatimprovetheperformanceandlowerthememoryconsumptionofyourapplications,beforemovingthemtoaproductionenvironment.

Page 29: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 30: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

WhatyouneedforthisbookInordertoruntheexamplesinthisbook,youwillneedtohaveawebserverinstalledonyoursystemtoservethecodefiles.Forexample,youcanuseApacheorIISorNGINX.InordertomaketheinstallationprocessofApacheeasier,youcanusemorecompletedevelopmentenvironmentsolutions,suchasXAMPPorWAMPServer.

Intermsoftechnicalproficiency,thisbookassumesthatyoualreadyhavesomeexperienceofworkingwithjQuery,HTML,CSS,andJSON.AllthecodesamplesinthebookusejQueryv2.2.0andsomeofthechaptersalsodiscusstherespectiveimplementationinjQueryv1.12.0,whichcanbeusedincasesupportforolderbrowsersisneeded.

Page 31: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 32: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

WhothisbookisforThisbooktargetsexistingjQuerydevelopersornewdeveloperswhowanttotaketheirskillsandunderstandingtoanadvancedlevel.ItisadetailedintroductiontohowthevariousindustrystandardpatternscanbeappliedtojQueryapplications,andalongwithasetofthebestpractices,itcanhelplargeteamscollaborateandcreatewellorganizedandextendableimplementations.

Page 33: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 34: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

ConventionsInthisbook,youwillfindanumberoftextstylesthatdistinguishbetweendifferentkindsofinformation.Herearesomeexamplesofthesestylesandanexplanationoftheirmeaning.

Codewordsintext,foldernames,filenames,fileextensions,pathnames,dummyURLs,userinput,andTwitterhandlesareshownasfollows:“IntheprecedingCSScode,wefirstdefinedsomebasicstylesforthebox,boxsizer,andclearCSSclasses.”

Ablockofcodeissetasfollows:

$.each([3,5,7],function(index){

console.log(this+1+'!');

});

Whenwewishtodrawyourattentiontoaparticularpartofacodeblock,therelevantlinesoritemsaresetinbold:

$('#categoriesSelector').change(function(){

var$selector=$(this);

varmessage={categoryID:$selector.val()};

broker.trigger('dashboardCategorySelect',[message]);

});

WearefollowingGoogle’sJavaScriptStyleGuide,exceptfromusingfourspacesforindentation,inordertoimprovethereadabilityofthecodeinthebook.Inshort,weareplacingcurlybracketsontopandusesinglequotesforstringliterals.

NoteFormoreinformationonGoogle’sJavaScriptStyleGuideyoucanvisitthefollowingURL:https://google.github.io/styleguide/javascriptguide.xml

Anycommand-lineinputoroutputiswrittenasfollows:

npminstalljquery

Newtermsandimportantwordsareshowninbold.Wordsthatyouseeonthescreen,forexample,inmenusordialogboxes,appearinthetextlikethis:“ThejQueryObjectreturnedisanArray-likeobjectthatactsasawrapperobjectandcarriesthecollectionoftheretrievedelements.”

NoteWarningsorimportantnotesappearinaboxlikethis.

TipTipsandtricksappearlikethis.

Page 35: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 36: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

ReaderfeedbackFeedbackfromourreadersisalwayswelcome.Letusknowwhatyouthinkaboutthisbook—whatyoulikedordisliked.Readerfeedbackisimportantforusasithelpsusdeveloptitlesthatyouwillreallygetthemostoutof.

Tosendusgeneralfeedback,simplye-mail<[email protected]>,andmentionthebook’stitleinthesubjectofyourmessage.

Ifthereisatopicthatyouhaveexpertiseinandyouareinterestedineitherwritingorcontributingtoabook,seeourauthorguideatwww.packtpub.com/authors.

Page 37: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 38: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

CustomersupportNowthatyouaretheproudownerofaPacktbook,wehaveanumberofthingstohelpyoutogetthemostfromyourpurchase.

Page 39: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

DownloadingtheexamplecodeYoucandownloadtheexamplecodefilesfromyouraccountathttp://www.packtpub.comforallthePacktPublishingbooksyouhavepurchased.Ifyoupurchasedthisbookelsewhere,youcanvisithttp://www.packtpub.com/supportandregistertohavethefilese-maileddirectlytoyou.

Page 40: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

ErrataAlthoughwehavetakeneverycaretoensuretheaccuracyofourcontent,mistakesdohappen.Ifyoufindamistakeinoneofourbooks—maybeamistakeinthetextorthecode—wewouldbegratefulifyoucouldreportthistous.Bydoingso,youcansaveotherreadersfromfrustrationandhelpusimprovesubsequentversionsofthisbook.Ifyoufindanyerrata,pleasereportthembyvisitinghttp://www.packtpub.com/submit-errata,selectingyourbook,clickingontheErrataSubmissionFormlink,andenteringthedetailsofyourerrata.Onceyourerrataareverified,yoursubmissionwillbeacceptedandtheerratawillbeuploadedtoourwebsiteoraddedtoanylistofexistingerrataundertheErratasectionofthattitle.

Toviewthepreviouslysubmittederrata,gotohttps://www.packtpub.com/books/content/supportandenterthenameofthebookinthesearchfield.TherequiredinformationwillappearundertheErratasection.

Page 41: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

PiracyPiracyofcopyrightedmaterialontheInternetisanongoingproblemacrossallmedia.AtPackt,wetaketheprotectionofourcopyrightandlicensesveryseriously.IfyoucomeacrossanyillegalcopiesofourworksinanyformontheInternet,pleaseprovideuswiththelocationaddressorwebsitenameimmediatelysothatwecanpursuearemedy.

Pleasecontactusat<[email protected]>withalinktothesuspectedpiratedmaterial.

Weappreciateyourhelpinprotectingourauthorsandourabilitytobringyouvaluablecontent.

Page 42: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

QuestionsIfyouhaveaproblemwithanyaspectofthisbook,youcancontactusat<[email protected]>,andwewilldoourbesttoaddresstheproblem.

Page 43: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 44: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

Chapter1.ARefresheronjQueryandtheCompositePatternUntiltheWeb2.0erastarted,theWebwasjustadocument-basedmediaandallitofferedwasjustinterconnectingdifferentpages/documentsandclient-sidescriptingthatwasmostlylimitedtoformvalidation.By2005,GmailandGoogleMapswerereleased,andJavaScriptproveditselfasalanguageusedbybigenterprisestocreatelarge-scaleapplicationsandproviderichuserinterfaceinteractions.

EventhoughJavaScripthashadveryfewchangessinceitsoriginalrelease,therewasatremendouschangeintheexpectationsthattheEnterpriseworldhadaboutwhatwebpagesshouldbecapableofdoing.Sincethen,webdeveloperswererequiredtodelivercomplexuserinteractionsand,finally,theterm“webapplication”appearedonthemarket.Asaresult,itstartedtobecomeobviousthattheyshouldcreatesomecodeabstractions,definesomebestpractices,andadoptalltheapplicableDesignPatternsthatcomputersciencehadtooffer.ThewideadoptionofJavaScriptforenterprise-gradeapplicationshelpedtheevolutionofthelanguage,whichwiththeEcmaScript2015/EcmaScript6(ES6)specificationwasexpandedinawaythatallowedevenmoreDesignPatternstobeeasilyutilized.

InAugust2006,thejQuerylibrarywasfirstreleasedbyJohnResigathttp://jquery.com,asanefforttocreateaconvenientAPItolocateDOMelements.Sincethen,ithasbeenanintegralpartofawebdeveloper’stoolkit.jQueryinitscoreusesseveralDesignPatternsandtriestourgetheirusetothedeveloperthroughthemethodsthatitprovides.TheCompositePatternisoneofthemanditisexposedtothedeveloperthroughtheverycorejQuery()method,whichisusedforDOMtraversal,oneofthehighlightsofthejQuerylibrary.

Inthischapter,wewill:

HavearefresheronDOMscriptingusingjQueryIntroducetheCompositePatternSeehowtheCompositePatternisusedbyjQueryDiscussthegainsofferedbyjQueryoverplainJavaScriptDOMmanipulationsIntroducetheIteratorPatternUsetheIteratorPatterninanexampleapplication

Page 45: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

jQueryandDOMscriptingByDOMscripting,werefertoanyprocedurethataltersormanipulatestheelementsofawebpageafterithasbeenloadedbythebrowser.TheDOMAPIisaJavaScriptAPIthatwasstandardizedin1998anditprovidestowebdevelopersacollectionofmethodsthatallowthemanipulationoftheDOMtreeelementsthatthebrowsercreatesafterloadingandparsingthewebpage’sHTMLcode.

NoteFormoreinformationontheDocumentObjectMode(DOM)anditsAPIs,youcanvisithttps://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Introduction.

ByutilizingtheDOMAPIintheirJavaScriptcode,webdeveloperscanmanipulatetheDOM’snodesandaddnewelementsorremoveexistingelementsfromthepage.TheprimaryusecaseforDOMscriptingwasinitiallylimitedtoclient-sideformvalidation,butastheyearspassedandJavaScriptgainedthetrustoftheEnterpriseworld,morecomplexuserinteractionsstartedtobeimplemented.

TheinitialversionofthejQuerylibrarywasfirstreleasedinAugust2006andittriedtoeasethewaythewebdevelopersweretraversingandmanipulatingtheDOMtree.Oneofitsmaingoalswastoprovideabstractionsthatresultedinshorter,easier-to-read,andlesserror-pronecode,whilealsoensuringcross-browserinteroperability.

ThesecoreprinciplesthatjQueryfollowsareclearlyvisibleinitshomepage,whereitpresentsitselfas:

…afast,small,andfeature-richJavaScriptlibrary.ItmakesthingslikeHTMLdocumenttraversalandmanipulation,eventhandling,animation,andAjaxmuchsimplerwithaneasy-to-useAPIthatworksacrossamultitudeofbrowsers.Withacombinationofversatilityandextensibility,jQueryhaschangedthewaythatmillionsofpeoplewriteJavaScript.

TheabstractedAPIsthatjQueryprovidedfromthebeginning,andthewaythatdifferentDesignPatternswereorchestrated,ledtowideacceptanceamongthewebdevelopers.Asaresult,thejQuerylibraryisreferencedbymorethan60%ofthemostvisitedwebsitesworldwide,accordingtoseveralsourcessuchasBuiltWith.com(http://trends.builtwith.com/javascript/jQuery).

Page 46: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

ManipulatingtheDOMusingjQueryTohavearefresheronjQuery,wewillgothroughanexamplewebpagethatdoessomesimpleDOMmanipulations.Inthisexample,wewillloadasimplystructuredpagethatinitiallylookslikethefollowingfigure:

WewillusesomejQuerycodetochangethepage’scontentandlayoutand,inordertomakeitseffectsclearlyvisible,wewillsetittorunabout700millisecondsafterthepagehasloaded.Theresultofourmanipulationswilllooklikethefollowingfigure:

Page 47: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

Nowlet’sreviewtheHTMLcoderequiredfortheprecedingexample:

<!DOCTYPEhtml>

<html>

<head>

<title>DOMManipulations</title>

<linkrel="stylesheet"type="text/css"href="dom-manipulations.css">

</head>

<body>

<h1id="pageHeader">DOMManipulations</h1>

<divclass="boxContainer">

<div>

<pclass="box">

DoingDOMManipulationsiseasywithJS!

</p>

</div>

<div>

<pclass="box">

DoingDOMManipulationsiseasywithJS!

</p>

</div>

<div>

<pclass="box">

DoingDOMManipulationsiseasywithJS!

</p>

</div>

</div>

<pclass="box">

DoingDOMManipulationsiseasywithJS!

</p>

<pclass="box">

DoingDOMManipulationsiseasywithJS!

</p>

<scripttype="text/javascript"src="https://code.jquery.com/jquery-

2.2.0.min.js"></script>

<scripttype="text/javascript"src="jquery-dom-manipulations.js">

</script>

</body>

</html>

TheCSScodeusedisquitesimple,containingonlythreeCSSclassesasfollows:

.box{

padding:7px10px;

border:solid1px#333;

margin:5px3px;

box-shadow:01px2px#777;

}

.boxsizer{

float:left;

width:33.33%;

}

Page 48: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

.clear{clear:both;}

TheprecedingcoderesultsinapagelookinglikethefirstfigurewhenopenedinabrowserandbeforeourJavaScriptcodeisexecuted.IntheprecedingCSScode,wefirstdefinedsomebasicstylesforthebox,boxsizer,andclearCSSclasses.Theboxclassstylestheassociatedelementsfoundinthepagebyusingsomepadding,athinborder,somemarginaround,andasmallshadowbelowtheelementsinordertomakethemlooklikeabox.Theboxsizerclasswillmaketheelementsthatuseittotakejust1/3rdofthewidthoftheirparentelementandcreateathree-columnlayout.Finally,theclearclasswillbeusedonanelementasabreakpointforthecolumnlayoutsothatalltheelementsthatfollowwillbepositionedbelowit.TheboxsizerandclearclassesarenotinitiallyusedbyanyelementdefinedintheHTMLcode,butwillbeusedaftertheDOMmanipulationsthatwewilldoinJavaScript.

Inthe<body>elementofourHTML,weinitiallydefinean<h1>headingelementwithIDpageHeadersothatitiseasilyselectablethroughJavaScript.Rightbelowit,wedefinefiveparagraphelements(<p>)withtheboxclass,havingthefirstthreeofthemwrappedinsidethethree<div>elementsandtheninsideanother<div>elementwiththeboxContainerclass.

Reachingourtwo<script>tags,wefirstincludeareferencetothejQuerylibraryfromjQueryCDN.Formoreinformation,youcanvisithttp://code.jquery.com/.Inthesecond<script>tag,wereferencetheJavaScriptfilewiththerequiredcode,forthisexample,whichlooksasfollows:

setTimeout(function(){

$('#pageHeader').css('font-size','3em');

var$boxes=$('.boxContainer.box');

$boxes.append(

'<br/><br/><i>Incaseweneedsimplethings</i>.');

$boxes.parent().addClass('boxsizer');

$('.boxContainer').append('<divclass="clear">');

},700);

AllourcodeiswrappedinsideasetTimeoutcalltodelayitsexecution,accordingtotheusecasedescribedearlier.ThefirstparameterofthesetTimeoutfunctioncallisananonymousfunctionthatwillbeexecutedafteratimerof700millisecondshasexpired,asdefinedinthesecondargument.

Atthefirstlineofouranonymouscallbackfunction,weusethejQuery$()functiontotraversetheDOMandlocatetheelementwiththeIDpageHeader,andusethecss()methodtoincreaseitsfont-sizeto3em.NextweprovideamorecomplexCSSselectortothe$()function,tolocatealltheelementswiththeboxclassthataredescendantsoftheelementwiththeboxContainerclass,andthenstoretheresultinavariablenamed$boxes.

Tip

Page 49: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

Variablenamingconventions

Itisacommonpracticeamongdeveloperstousenamingconventionsforvariablesthatholdobjectsofacertaintype.Usingsuchconventionsnotonlyhelpsyourememberwhatthevariableisholding,butalsomakesyourcodeeasiertounderstandbyotherdevelopersofyourteam.AmongjQuerydevelopers,itiscommontousevariablenamesstartingwitha“$”signwhenthevariablestorestheresultofthe$()function(alsoknowasajQuerycollectionobject).

Afterwegetaholdoftheboxelementsthatweareinterestedin,weappendtwobreakingspacesandsomeextratextinitalics,attheendofeachofthem.Then,weusethe$boxesvariableandtraversetheDOMtreeonelevelup,usingtheparent()method.Theparent()methodreturnsadifferentjQueryobjectholdingtheparent<div>elementsofourinitiallyselectedboxesandthenwechainacalltotheaddClass()methodtoassignthemtheboxsizerCSSclass.

TipIfyouneedtotraversealltheparentnodesofaselectedelement,youcanusethe$.fn.parents()method.IfyoujustneedtofindthefirstancestorelementthatmatchesagivenCSSselector,considerusingthe$.fn.closest()methodinstead.

Finally,sincetheboxsizerclassusesfloatstoachievethethree-columnlayout,weneedtoclearthefloatsintheboxContainer.Onceagain,wetraversetheDOMusingthesimple.boxContainerCSSselectorandthe$()function.Then,wecallthe.append()methodtocreateanew<div>elementwiththe.clearCSSclassandinsertitattheendoftheboxContainer.

After700milliseconds,ourjQuerycodewillhavefinished,resultinginthethree-columnlayoutasshownearlier.Initsfinalstate,theHTMLcodeofourboxContainerelementwilllookasfollows:

<divclass="boxContainer">

<divclass="boxsizer">

<pclass="box">

DoingDOMManipulationsiseasywithJS!

<br><br><i>Incaseweneedsimplethings</i>.

</p>

</div>

<divclass="boxsizer">

<pclass="box">

DoingDOMManipulationsiseasywithJS!

<br><br><i>Incaseweneedsimplethings</i>.

</p>

</div>

<divclass="boxsizer">

<pclass="box">

DoingDOMManipulationsiseasywithJS!

<br><br><i>Incaseweneedsimplethings</i>.

</p>

</div>

<divclass="clear"></div>

Page 50: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

</div>

MethodChainingandFluentInterfacesActually,intheprecedingexample,wecanalsogoonestepfurtherandcombineallthreebox-relatedcodestatementsintojustone,whichlookssomethingasfollows:

$('.boxContainer.box')

.append('<br/><br/><i>Incaseweneedsimplethings</i>.')

.parent()

.addClass('boxsizer');

ThisSyntaxPatterniscalledMethodChaininganditishighlyrecommendedbyjQueryandtheJavaScriptcommunityingeneral.MethodChainingispartoftheObjectOrientedImplementationPatternofFluentInterfaceswhereeachmethodrelaysitsinstructioncontexttothesubsequentone.

MostjQuerymethodsthatapplyonajQueryobjectalsoreturnthesameoranewjQueryelementcollectionobject.Thisallowsustochainseveralmethods,notonlyresultinginamorereadableandexpressivecodebutalsoreducingtherequiredvariabledeclarations.

Page 51: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 52: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

TheCompositePatternThekeyconceptoftheCompositePatternistoenableustotreatacollectionofobjectsinthesamewayaswetreatasingleobjectinstance.Manipulatingacompositionbyusingamethodonthecollectionwillresultinapplyingthemanipulationtoeachpartofit.Suchmethodscanbeappliedsuccessfully,regardlessofthenumberofelementsthatarepartofthecompositecollection,orevenwhenthecollectioncontainsnoelements.

Also,theobjectsofacompositecollectiondonotnecessarilyhavetoprovidetheexactsamemethods.TheCompositeObjectcaneitherexposeonlythemethodsthatarecommonamongtheobjectsofthecollection,orcanprovideanabstractedAPIandappropriatelyhandlethemethoddifferentiationsofeachobject.

Let’scontinuebyexploringhowtheintuitiveAPIthatjQueryexposesishighlyinfluencedfromtheCompositePattern.

Page 53: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

HowtheCompositePatternisusedbyjQueryTheCompositePatternisanintegralpartofjQuery’sarchitectureandisappliedfromtheverycore$()functionitself.Eachcalltothe$()functioncreatesandreturnsanelementcollectionobject,whichisoftensimplyreferredasajQueryobject.ThisisexactlywhereweseethefirstprincipleoftheCompositePatterns;infact,insteadofreturningasingleelement,the$()functionreturnsacollectionofelements.

ThejQueryobjectreturnedisanArray-likeobjectthatactsasawrapperobjectandcarriesthecollectionoftheretrievedelements.Italsoexposesanumberofextrapropertiesasfollows:

ThelengthoftheretrievedelementcollectionThecontextthattheobjectwasconstructedTheCSSselectorthatwasusedonthe$()functioncallAprevObjectpropertyincaseweneedtoaccessthepreviouselementcollectionafterchainingamethodcall

TipSimpleArray-likeobjectdefinition

AnArray-likeobjectisaJavaScriptobject{}thathasanumericlengthpropertyandtherespectivenumberofproperties,withsequentialnumericpropertynames.Inotherwords,anArray-likeobjectthathasthelength==2propertyisexpectedtoalsohavetwopropertiesdefined,"0"and"1".Giventheaboveproperties,Array-likeobjectsallowyoutoaccesstheircontentusingsimpleforloops,byutilizingJavaScript’sBracketPropertyAccessor’ssyntax:

for(vari=0;i<obj.length;i++){

console.log(obj[i]);

}

WecaneasilyexperimentwiththejQueryobjectsreturnedfromthe$()functionandinspectthepropertiesdescribedabove,byusingthedevelopertoolsofourfavoritebrowser.Toopenthedevelopertoolsonmostofthem,wejustneedtopressF12onWindowsandLinuxorCmd+Opt+IonMac,andrightafterthat,wecanissuesome$()callsintheconsoleandclickonthereturnedobjectstoinspecttheirproperties.

Inthefollowingfigure,wecanseewhattheresultofthe$('#pageHeader')call,whichweusedintheexampleearlier,lookslikeinFirefoxDeveloperTools:

Theresultofthe$('.boxContainer.box')calllooksasfollows:

Page 54: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

ThefactthatjQueryusesArray-likeobjectsasawrapperforthereturnedelementsallowsittoexposesomeextramethodsthatapplyonthecollectionreturned.ThisisachievedthroughprototypicalinheritanceofthejQuery.fnobject,resultingineachjQueryobjectalsohavingaccesstoallthemethodsthatjQueryprovides.ThiscompletestheCompositePattern,whichprovidesmethodsthat,whenappliedtoacollection,areappropriatelyappliedtoeachofitsmembers.BecausejQueryusesArray-likeobjectswithprototypicalinheritance,thesemethodscanbeeasilyaccessedaspropertiesoneachjQueryobject,asshownintheexampleinthebeginningofthechapter:$('#pageHeader').css('font-size','3em');.Moreover,jQueryaddssomeextragoodiestoitsDOMmanipulatingcode,followingthegoalofsmallerandlesserror-pronecode.Forexample,whenusingthejQuery.fn.html()methodtochangetheinnerHTMLofaDOMnodethatalreadycontainschildelements,jQueryfirsttriestoremoveanydataandeventhandlersthatareassociatedwiththechildelements,beforeremovingthemfromthepageandappendingtheprovidedHTMLcode.

Let’stakealookathowjQueryimplementsthesecollection-applicablemethods.Forthistask,wecaneitherdownloadandviewthesourcecodefromtheGitHubpageofjQuery(https://github.com/jquery/jquery/releases),orwecanuseatoolsuchasthejQuerySourceViewerthatisavailableathttp://james.padolsey.com/jquery.

NoteDependingontheversionyouareusing,youmightgetdifferentresultstosomedegree.ThemostrecentstablejQueryversionthatwasreleasedandusedasareferencewhilewritingthisbook,wasv2.2.0.

Oneofthesimplestmethodstodemonstratehowmethodsthatapplytocollectionsareimplemented,isjQuery.fn.empty().YoucaneasilylocateitsimplementationinjQuery’ssourcecodebysearchingfor"empty:"orusingthejQuerySourceViewerandsearchingfor"jQuery.fn.empty".Usingeitheroneofthewayswillbringustothefollowingcode:

empty:function(){

varelem,i=0;

for(;(elem=this[i])!=null;i++){

if(elem.nodeType===1){

//Preventmemoryleaks

jQuery.cleanData(getAll(elem,false));

//Removeanyremainingnodes

Page 55: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

elem.textContent="";

}

}

returnthis;

}

Asyoucansee,thecodeisnotcomplexatall.jQueryiteratesoveralltheitemsofthecollectionobject(referredtoasthissinceweareinsidethemethodimplementation)byusingaplainforloop.Foreachitemofthecollection,thatis,anElementNode,itclearsanydata-*propertyvaluesusingthejQuery.cleanData()helperfunction,andrightafterthis,itclearsitscontentbysettingittoanemptystring.

NoteFormoreinformationonthedifferentspecifiedNodeTypes,youcanvisithttps://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType.

Page 56: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

ComparingthebenefitsovertheplainDOMAPIToclearlydemonstratethebenefitsthattheCompositePatternprovides,wewillrewriteourinitialexamplewithouttheabstractionsthatjQueryoffers.ByusingjustplainJavaScriptandtheDOMAPI,wecanwriteanequivalentcodethatlooksasfollows:

setTimeout(function(){

varheaderElement=document.getElementById('pageHeader');

if(headerElement){

headerElement.style.fontSize='3em';

}

varboxContainerElement=document.getElementsByClassName('boxContainer')

[0];

if(boxContainerElement){

varinnerBoxElements=

boxContainerElement.getElementsByClassName('box');

for(vari=0;i<innerBoxElements.length;i++){

varboxElement=innerBoxElements[i];

boxElement.innerHTML+='<br/><br/><i>Incaseweneedsimple

things</i>.';

boxElement.parentNode.className+='boxsizer';

}

varclearFloatDiv=document.createElement('div');

clearFloatDiv.className='clear';

boxContainerElement.appendChild(clearFloatDiv);

}

},700);

Onceagain,weusesetTimeoutwithananonymousfunctionandset700millisecondsasthesecondparameter.Insidethefunctionitself,weusedocument.getElementByIdtoretrieveelementsthatareknowntohaveauniqueIDinthepage,andlaterdocument.getElementsByClassNamewhenweneedtoretrievealltheelementsthathaveaspecificclass.WealsouseboxContainerElement.getElementsByClassName('box')toretrievealltheelementswiththeboxclassthataredescendantsoftheelementwiththeboxContainerclass.

Themostobviousobservationisthat,inthiscase,weneeded18linesofcodeinordertoachievethesameresults.Forcomparison,whenusingjQuery,weonlyneeded9linesofcode,that’shalfthenumberoflinesofcodecomparedtothelaterimplementation.UsingthejQuery$()functionwithaCSSselectorwasaneasierwaytoretrievetheelementsthatweneeded,anditalsoensurescompatibilitywithbrowsersthatdonotsupportthegetElementsByClassName()method.However,therearemorebenefitsthanjustthecodelinecountandtheimprovedreadability.AsanimplementeroftheCompositePattern,the$()functionalwaysretrieveselementcollections,makingourcodemoreuniformwhencomparedtothedifferentiatedhandlingofeachgetElement*methodweused.Weusethe$()functioninexactlythesameway,regardlessofwhetherwejustwanttoretrieveanelementwithauniqueIDoranumberofelementswithaspecificclass.

AsanextrabenefitofreturningArray-likeobjects,jQuerycanalsoprovidemoreconvenientmethodstotraverseandmanipulatetheDOM,suchasthosewesawinourfirstexample,.css(),.append()and.parent(),whichareaccessibleaspropertiesofthe

Page 57: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

returnedobject.Additionally,jQueryalsooffersmethodsthatabstractmorecomplexusecasessuchas.addClass()and.wrap()thathavenoequivalentmethodsavailableaspartoftheDOMAPI.

SincethereturnedjQuerycollectionobjectsdonotdifferinanythingotherthantheelementstheywrap,wecanuseanymethodofthejQueryAPIinthesameway.Aswesawearlier,thesemethodsapplytoeachelementoftheretrievedcollection,regardlessoftheelementcount.Asaresult,wedonotneedaseparateforlooptoiterateovereachretrievedelementandapplyourmanipulationsindividually;instead,weapplyourmanipulations(forexample,.addClass())directlytothecollectionobject.

Tocontinueprovidingthesameexecutionsafetyguarantiesinthelaterexample,wealsoneedtoaddsomeextraifstatementstocheckfornullvalues.Thisisrequiredbecause,forexample,iftheheaderElementisnotfound,anerrorwilloccurandtherestofthelinesofcodewillneverbeexecuted.Someonecouldarguethatthesechecks,suchasif(headerElement)andif(boxContainerElement),arenotrequiredinthisexampleandcanbeomitted.Thismightappeartobecorrectinthisexample,butactuallythisisamongthetopreasonsforerrorswhiledevelopinglarge-scaleapplications,whereelementsarecreated,inserted,andremovedfromtheDOMtreecontinuously.Unfortunately,programmersinalllanguagesandtargetplatformstendtofirstwritetheirimplementationlogicandfillsuchchecksatalatertime,oftenaftertheygetanerrorwhentestingtheirimplementation.

FollowingtheCompositePattern,evenanemptyjQuerycollectionobject(onethatcontainsnoretrievedelements)isstillavalidcollectionobject,wherewecansafelyapplyanymethodthatjQueryprovides.Asaresult,wedonotneedtheextraifstatementstocheckwhetheracollectionactuallycontainsanyelementbeforeapplyingamethodsuchas.css(),justforthesakeofavoidingaJavaScriptruntimeerror.

Overall,theabstractionsthatjQueryoffersbyusingtheCompositePatternleadtofewerlinesofcode,whichismorereadable,uniform,andwithfewertypo-pronelines(comparetyping$('#elementID')versusdocument.getElementById('elementID')).

Page 58: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

UsingtheCompositePatterntodevelopapplicationsNowthatwehaveseenhowjQueryusestheCompositePatterninitsarchitectureandalsodidacomparisononthebenefitsitprovided,let’strytowriteanexampleusecaseofourown.Wewilltrytocoverallconceptsthatwehaveseenearlierinthischapter.WewillstructureourCompositetobeanArray-likeobject,operateontotallydifferentstructuredobjects,provideaFluentAPItoallowchaining,andhavemethodsthatapplyonalltheitemsofthecollection.

AsampleusecaseLet’ssaythatwehaveanapplicationthatatsomepointneedstoperformoperationsonnumbers.Ontheotherhand,theitemsthatitneedstooperateoncomefromdifferentsourcesandarenotuniformatall.Tomakethisexampleinteresting,let’ssupposethatonesourceofdataprovidesplainnumbersandanotheroneprovidesobjectswithaspecificpropertythatholdsthenumberweareinterestedin:

varnumberValues=[2,5,8];

varobjectsWithValues=[

{value:7},

{value:4},

{value:6},

{value:9}

];

Theobjectsreturnedbythesecondsourceofourusecasecouldhaveamorecomplexstructureandprobablysomeextraproperties.Suchchangeswouldn’tdifferentiateourexampleimplementationinanyway,sincewhendevelopingaCompositeweareonlyinterestedinprovidingauniformhandlingoverthecommonpartsbetweenthetargeteditems.

TheCompositeCollectionImplementationLet’sproceedanddefinetheConstructorFunctionandtheprototypethatwilldescribeourCompositeCollectionObject:

functionValuesComposite(){

this.length=0;

}

ValuesComposite.prototype.append=function(item){

if((typeofitem==='object'&&'value'initem)||

typeofitem==='number'){

this[this.length]=item;

this.length++;

}

returnthis;

};

Page 59: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

ValuesComposite.prototype.increment=function(number){

for(vari=0;i<this.length;i++){

varitem=this[i];

if(typeofitem==='object'&&'value'initem){

item.value+=number;

}elseif(typeofitem==='number'){

this[i]+=number;

}

}

returnthis;

};

ValuesComposite.prototype.getValues=function(){

varresult=[];

for(vari=0;i<this.length;i++){

varitem=this[i];

if(typeofitem==='object'&&'value'initem){

result.push(item.value);

}elseif(typeofitem==='number'){

result.push(item);

}

}

returnresult;

};

TheValuesComposite()constructorfunctioninourexampleisquitesimple.Wheninvokedwiththenewoperator,itreturnsanemptyobjectwithalengthpropertyequaltozero,representingthatthecollectionitwrapsisempty.

NoteFormoreinformationonthePrototype-basedprogrammingmodelofJavaScript,visithttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Introduction_to_Object-Oriented_JavaScript.

Wefirstneedtodefineawaythatwillenableustopopulateourcompositecollectionobjects.Wedefinedtheappendmethodthatcheckswhethertheprovidedparameterisoneofthetypesthatitcanhandle;inthiscase,itappendstheparameterontheCompositeObjectonthenextavailablenumericpropertyandincrementsthelengthpropertyvalue.Forexample,thefirstappendeditem,whetheritisanobjectwithavaluepropertyoraplainnumber,willbeexposedtothe“0”propertyoftheCompositeObjectandwillbeaccessiblewiththeBracketPropertyAccessor’ssyntaxasmyValuesComposition[0].

Theincrementmethodispresentedasasimpleexamplemethodthatcanmanipulatesuchcollectionsbyoperatingoverallthecollectionitems.Itacceptsanumericvalueasaparameterandthenappropriatelyhandlesitbyaddingittoeachitemofourcollection,basedontheirtype.SinceourcompositeisanArray-likeobject,incrementusesaforlooptoiterateoverallthecollectionitemsandeitherincreasestheitem.value(incasetheitemisanobject)ortheactualnumericvaluestored(whenthecollectionitemstoredisanumber).Inthesamemanner,wecancontinueandimplementothermethodsthatwill,

Page 60: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

forexample,enableustomultiplythecollectionitemswithaspecificnumber.

InordertoallowchainingthemethodsofourCompositeObject,allthemethodsoftheprototypeneedtoreturnareferencetotheinstanceoftheobject.Weachievethisgoalbysimplyaddingareturnthis;statementasthelastlineforallthemethodsthatmanipulatethecollection,suchasappendandincrement.KeepinmindthatmethodssuchasgetValuesthatdonotmanipulatethecollectionbutareusedtoreturnaresult,bydefinition,can’tbechainedtorelaythecollectionobjectinstancetosubsequentmethodcalls.

Finally,weimplementthegetValuesmethodasaconvenientwaytoretrievetheactualnumericvaluesofalltheitemsinourcollection.Similartotheincrementmethod,thegetValuesmethodabstractsawaythehandlingbetweenthedifferentitemtypesofourcollection.Ititeratesoverthecollectionitems,extractseachnumericvalue,andappendsthemtoaresultarraythatitreturnstoitscaller.

AnexampleexecutionLet’snowseeanactualexamplethatwillusetheCompositeObjectwejustimplemented:

varvaluesComposition=newValuesComposite();

for(vari=0;i<numberValues.length;i++){

valuesComposition.append(numberValues[i]);

}

for(vari=0;i<objectsWithValues.length;i++){

valuesComposition.append(objectsWithValues[i]);

}

valuesComposition.increment(2)

.append(1)

.append(2)

.append({value:3});

console.log(valuesComposition.getValues());

Whentheprecedingcodeisexecutedinabrowser,bywritingthecodeeitherinanexistingpageordirectlyinthebrowser’sconsole,itwilllogaresultthatlooksasfollows:

►Array[4,7,10,9,6,8,11,1,2,3]

WeareusingourdatasourcessuchasthenumberValuesandobjectsWithValuesvariablesthatwereshownearlier.TheprecedingcodeiteratesoverbothofthemandappendstheiritemstoanewlycreatedCompositeObjectinstance.Wethenproceedbyincrementingthevaluesofourcompositecollectionby2.Rightafterthis,wechainthethreeiteminsertionsusingappend,withthefirsttwoappendingnumericvaluesandthethirdappendinganobjectwithavalueproperty.Finally,weusethegetValuesmethodinordertogetanarraywithallthenumericvaluesofourcollectionandlogitinourbrowser’sconsole.

Alternativeimplementations

Page 61: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

KeepinmindthataCompositedoesnotneedtobeanArray-likeobject,butiscommonlypreferredsinceJavaScriptmakesiteasytocreatesuchanimplementation.Additionally,Array-likeimplementationsalsohavethebenefitofallowingustoiterateoverthecollectionitemsusingasimpleforloop.

Ontheotherhand,incaseanArray-likeobjectisnotpreferred,wecaneasilyuseapropertyontheCompositeObjecttoholdourcollectionitems.Forexample,thispropertycanbenamedasitemsandbeusedtostoreandaccesstheitemsofthecollectioninsideourmethodsusingthis.items.push(item)andthis.items[i],respectively.

Page 62: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 63: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

TheIteratorPatternThekeyconceptoftheIteratorPatternistheuseofafunctionwiththesingleresponsibilitytotraverseacollectionandprovideaccesstoitsitems.Thisfunctionisknownastheiteratorandprovidesawaytoaccesstheitemsofthecollection,withoutexposingimplementationspecificsandtheunderlyingdatastructureusedbythecollectionobject.

Iteratorsprovidealevelofencapsulationregardingthewaytheiterationoccurs,decouplingtheiterationovertheitemsofacollectionfromtheimplementationlogicoftheirconsumers.

NoteFormoreinformationontheSingleResponsibilityprinciple,youcanvisithttp://www.oodesign.com/single-responsibility-principle.html.

Page 64: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

HowtheIteratorPatternisusedbyjQueryAswesawearlierinthischapter,thejQuerycore$()functionreturnsanArray-likeobjectthatwrapsacollectionofpageelementsanditalsoprovidesaniteratorfunctiontotraverseitandaccesseachelementindividually.ItactuallygoesonestepfurtherandprovidesagenerichelpermethodjQuery.each()thatcaniterateoverarrays,Array-likeobjects,andalsoobjectproperties.

AmoretechnicaldescriptioncanbefoundinjQueryAPIdocumentationpageathttp://api.jquery.com/jQuery.each/,wherethedescriptionofjQuery.each()readsasfollows:

Agenericiteratorfunction,whichcanbeusedtoseamlesslyiterateoverbothobjectsandarrays.ArraysandArray-likeobjectswithalengthproperty(suchasafunction’sargumentsobject)areiteratedbynumericindex,from0tolength-1.Otherobjectsareiteratedviatheirnamedproperties.

ThejQuery.each()helperfunctionisusedinternallyinseveralplacesofthejQuerysourcecode.OneofitsusesisiteratingovertheitemsofajQueryobjectandapplyingmanipulationsoneachofthem,astheCompositePatternsuggests.Asimplesearchforthekeyword.each(reveals56matches.

NoteAsofwritingthisbook,thelateststableversionisv2.2.0andthiswasusedfortheabovestatistics.

WecaneasilytraceitsimplementationinjQuery’ssource,eitherbysearchingfor"each:"(notethattherearetwooccurrences)orusingthejQuerySourceViewerandsearchingfor"jQuery.each()"(likewedidearlierinthischapter):

each:function(obj,callback){

varlength,i=0;

if(isArrayLike(obj)){

length=obj.length;

for(;i<length;i++){

if(callback.call(obj[i],i,obj[i])===false){

break;

}

}

}else{

for(iinobj){

if(callback.call(obj[i],i,obj[i])===false){

break;

}

}

}

returnobj;

}

Page 65: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

ThishelperfunctionisalsoaccessibleonanyjQueryobjectbyusingthesameprototypicalinheritancethatwesawearlierformethodssuchas.append().Youcaneasilyfindthecodethatdoesexactlythis,bysearchingfor"jQuery.fn.each()"injQuerySourceViewerordirectlysearchingjQuerysourcecodeforeach:(notethattherearetwooccurrences):

each:function(callback){

returnjQuery.each(this,callback);

}

Usingthemethodversionof".each()"enablesustodirectlyiterateovertheelementsofajQuerycollectionobjectwithamoreconvenientsyntax.

Theexamplecodethatfollowsshowcaseshowthetwoflavorsof.each()canbeusedinourcode:

//usingthehelperfunctiononanarray

$.each([3,5,7],function(index){

console.log(this+1);

});

//usingthemethodonajQueryobject

$('.boxContainer.box').each(function(index){

console.log('I\'mbox#'+(index+1));//indexiszero-based

});

Whenexecuted,theprecedingcodewilllogthefollowingonthebrowser’sconsole:

Page 66: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

HowitpairswiththeCompositePatternSincetheCompositePatternencapsulatesacollectionofitemsintoasingleobjectandtheIteratorPatterncanbeusedtoiterateoveranabstracteddatastructure,wecaneasilycharacterizethesetwopatternsascomplementary.

Page 67: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

WherecanitbeusedTheIteratorPatterncanbeusedinourapplicationstoabstractthewayweaccessitemsfromadatastructure.Forexample,let’ssupposeweneedtoretrievealltheitemsthataregreaterthan4fromthefollowingtreestructure:

varcollection={

nodeValue:7,

left:{

nodeValue:4,

left:2,

right:{

nodeValue:6,

left:5,

right:9

}

},

right:{

nodeValue:9,

left:8

}

};

Let’snowimplementouriteratorfunction.Sincetreedatastructurescanhavenesting,weendupwiththefollowingrecursiveimplementation:

functioniterateTreeValues(node,callback){

if(node===null||node===undefined){

return;

}

if(typeofnode==='object'){

if('left'innode){

iterateTreeValues(node.left,callback);

}

if('nodeValue'innode){

callback(node.nodeValue);

}

if('right'innode){

iterateTreeValues(node.right,callback);

}

}else{

//itsaleaf,sothenodeisthevalue

callback(node);

}

}

Finally,weendupwithanimplementationthatlooksasfollows:

varvaluesArray=[];

iterateTreeValues(collection,function(value){

if(value>4){

valuesArray.push(value);

}

});

Page 68: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

console.log(valuesArray);

Whenexecuted,theprecedingcodewilllogthefollowingonthebrowser’sconsole:

►Array[5,6,9,7,8,9]

Wecanclearlyseethattheiteratorsimplifiedourcode.Wenolongerbotherwiththeimplementationspecificsofthedatastructureusedeverytimeweneedtoaccesssomeitemsthatfulfillcertaincriteria.OurimplementationworksontopofthegenericAPIthattheiteratorexposes,andourimplementationlogicappearsinthecallbackthatweprovidetotheiterator.

Thisencapsulationallowsustodecoupleourimplementationfromthedatastructureused,giventhataniteratorwiththesameAPIwillbeavailable.Forinstance,inthisexample,wecaneasilychangethedatastructureusedtoasortedbinarytreeorasimplearrayandpreserveourimplementationlogicthesame.

Page 69: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 70: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

SummaryInthischapter,wehadarefresheronJavaScript’sDOMScriptingAPIandjQuery.WewereintroducedtotheCompositePatternandsawhowitisusedbythejQuerylibrary.WesawhowtheCompositePatternsimplifiesourworkflowafterwerewroteourexamplepagewithoutusingjQuery,andlatershowcasedanexampleofusingtheCompositePatterninourapplications.Finally,wewereintroducedtotheIteratorPatternandsawhowwellitpairswhenusedalongwiththeCompositePattern.

NowthatwehavecompletedourintroductiononhowtheCompositePatternplaysanimportantroleinthewayweusejQuerymethodseveryday,wecanmoveontothenextchapterwherewewillshowcasetheObserverPatternandtheconvenientwaytoutilizeitinourpagesusingjQuery.

Page 71: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 72: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

Chapter2.TheObserverPatternInthischapter,wewillshowcasetheObserverPatternandtheconvenientwayinwhichwecanutilizeitinourpagesusingjQuery.Lateron,wewillalsoexplaintheDelegatedEventObserverPatternvariant,whichwhenproperlyappliedtowebpagescanleadtocodesimplificationsandalsolessenthememoryconsumptionthatapagerequires.

Inthischapter,wewill:

IntroducetheObserverPatternSeehowtheObserverPatternisusedbyjQueryComparetheObserverPatternwithusingtheeventattributesLearnhowtoavoidmemoryleaksfromobserversIntroducetheDelegatedEventObserverPatternandshowcasingitsbenefits

Page 73: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

IntroducingtheObserverPatternThekeyconceptoftheObserverPatternisthatthereisanobject,oftenreferredtoastheobservableorthesubject,whoseinternalstatechangesduringitslifetime.Therearealsoseveralotherobjects,referredastheobservers,thatwanttobenotifiedintheeventthatthestateoftheobservable/subjectchanges,inordertoexecutesomeoperations.

Theobserversmayneedtobenotifiedaboutanykindofstatechangeoftheobservableoronlyspecifictypesofchanges.Inthemostcommonimplementation,theobservablemaintainsalistwithitsobserversandnotifiesthemwhenanappropriatestatechangeoccurs.Incaseastatechangeoccurstotheobservable,ititeratesthroughthelistofobserversthatareinterestedforthattypeofstatechangeandexecutesaspecificmethodthattheyhavedefined.

AccordingtothedefinitionoftheObserverPatternandthereferenceimplementationinComputerSciencebooks,theobserversaredescribedasobjectsthatimplementawell-knownprogramminginterface,inmostcases,specifictoeachobservabletheyareinterestedin.Inthecaseofastatechange,theobservablewillexecutethewell-knownmethodofeachobserverasitisdefinedintheprogramminginterface.

NoteFormoreinformationonhowtheObserverPatternisusedintraditional,object-orientedprogramming,youcanvisithttp://www.oodesign.com/observer-pattern.html.

Inthewebstack,theObserverPatternoftenusesplainanonymouscallbackfunctionsasobserversinsteadofobjectswithwell-knownmethods.Anequivalentresult,asdefinedby

Page 74: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

theObserverPattern,canbeachievedsincethecallbackfunctionkeepsreferencestothevariablesoftheenvironmentthatitwasdefinedin—apatterncommonlyreferencedasaClosure.ThemainbenefitofusingtheObserverPatternovercallbacksasinvocationorinitializationparametersisthattheObserverPatterncansupportseveralindependenthandlersonasingletarget.

NoteFormoreinformationonclosures,youcanvisithttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures.

TipDefiningasimplecallback

Acallbackcanbedefinedasafunctionthatispassedasanargumenttoanotherfunction/methodorisassignedtoapropertyofanobjectandexpectedtobeexecutedatsomelaterpointoftime.Inthisway,thepieceofcodethatwashandedourcallbackwillinvokeorcallit,propagatingtheresultsofanoperationoreventbacktothecontextwherethecallbackwasdefined.

Sincethepatternofregisteringfunctionsasobservershasproventobemoreflexibleandstraightforwardtoprogram,itcanbefoundinprogramminglanguagesoutsidethewebstackaswell.Otherprogramminglanguagesprovideanequivalentfunctionalitythroughlanguagefeaturesorspecialobjectssuchassubroutines,lambdaexpressions,blocks,andfunctionpointers.Forexample,Pythonalsodefinesfunctionsasfirst-classobjectssuchasJavaScript,enablingthemtobeusedascallbacks,whileC#definesDelegatesasaspecialobjecttypeinordertoachievethesameresult.

TheObserverPatternisanintegralpartofdevelopingwebinterfacesthatrespondtouseractions,andeverywebdeveloperhasusedittosomedegree,evenwithoutnoticingit.Thisisbecausethefirstthingthatawebdeveloperneedstodowhilecreatingarichuserinterfaceistoaddeventlistenerstopageelementsanddefinehowthebrowsershouldrespondtothem.

ThisistraditionallyachievedbyusingtheEventTarget.addEventListener()methodonthepageelementsthatweneedtolistentoforeventssuchasa“click”,andprovidingacallbackfunctionwiththecodethatneedstobeexecutedwhenthateventoccurs.ItisworthmentioningthatinordertosupportolderversionsofInternetExplorer,testingfortheexistenceofEventTarget.attachEvent(),andusingthatinstead,isrequired.

NoteFormoreinformationontheaddEventListener()andattachEvent()methods,youcanvisithttps://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListenerandhttps://developer.mozilla.org/en-US/docs/Web/API/EventTarget/attachEvent.

Page 75: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

HowitisusedbyjQueryThejQuerylibraryheavilyusestheObserverPatterninseveralpartsofitsimplementation,eitherdirectlybyusingtheaddEventListenermethodorcreatingitsownabstractionoverit.Moreover,jQueryoffersaseriesofabstractionsandconvenientmethodstomakeworkingwiththeObserverPatterneasieronthewebandalsousessomeoftheminternallytoimplementothermethodsaswell.

ThejQueryonmethodThejQuery.fn.on()methodisthecentraljQuerymethodforattachingeventhandlerstoelements,providinganeasywaytoadopttheObserverPattern,whilekeepingourcodeeasytoreadandreason.ItattachestherequestedeventhandleroveralltheelementsofacompositejQuerycollectionobjectreturnedbythe$()function.

SearchingforjQuery.fn.oninjQuery’sSourceViewer(whichisavailableathttp://james.padolsey.com/jquery),ordirectlysearchingjQuery’ssourcecodeforon:function(thefirstcharacterisatab),willleadustothemethod’sdefinition,whichcounts67linesofcode.Actually,thefirst55linesoftheinternalonfunctionarejusthandlingallthedifferentwaysthatthejQuery.fn.on()methodcanbeinvoked;nearitsend,wecanseethatitactuallyusestheinternalmethodjQuery.event.add():

jQuery.fn.extend({

on:function(types,selector,data,fn){

returnon(this,types,selector,data,fn);

}

});

functionon(elem,types,selector,data,fn,one){

/*55linesofcodehandlingthemethodoverloads*/

returnelem.each(function(){

jQuery.event.add(this,types,fn,data,selector);

});

}

ThejQuery.eventobjectistheone-placestopforeventhandlinginjQueryanditsimplementationcountsaround443linesofcode.Itholdsseveralhelperfunctionsformanagingeventssuchasadd,dispatch,fix,handlers,remove,simulate,andtrigger.AllthesefunctionsareusedinternallybyjQueryitselfwherevertheObserverPatternappearsormanagingeventsisrequired.

SearchingforjQuery.event.addinjQuery’sSourceViewerorjQuery.event=directlyinjQuery’ssourcecode,willleadustotherelativelylongimplementationofthehelperfunctionthatcountsaround107linesofcodeinjQueryv2.2.0.Thefollowingcodesnippetshowsatrimmeddownversionofthatmethod,wheresomecoderelatedtothetechnicalimplementationofjQueryandnotrelatedtotheObserverPatternhasbeenremovedforclarity:

add:function(elem,types,handler,data,selector){

/*...4linesofcode…*/

Page 76: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

elemData=dataPriv.get(elem);

/*...13linesofcode…*/

//MakesurethatthehandlerhasauniqueID,

//usedtofind/removeitlater

if(!handler.guid){

handler.guid=jQuery.guid++;

}

//Inittheelement'seventstructureandmainhandler,

//ifthisisthefirst

if(!(events=elemData.events)){

events=elemData.events={};

}

/*...9linesofcode…*/

//Handlemultipleeventsseparatedbyaspace

types=(types||"").match(rnotwhite)||[""];

t=types.length;

while(t--){

/*...30linesofcode…*/

//Inittheeventhandlerqueueifwe'rethefirst

if(!(handlers=events[type])){

handlers=events[type]=[];

handlers.delegateCount=0;

//OnlyuseaddEventListenerifthespecialeventshandler

//returnsfalse

if(!special.setup||special.setup.call(elem,data,

namespaces,eventHandle)===false){

if(elem.addEventListener){

elem.addEventListener(type,eventHandle);

}

}

}

/*...9linesofcode…*/

//Addtotheelement'shandlerlist,delegatesinfront

if(selector){

handlers.splice(handlers.delegateCount++,0,handleObj);

}else{

handlers.push(handleObj);

}

/*...3linesofcode…*/

}

}

Now,let’sseehowtheObserverPatternisimplementedbyjQuery.event.add(),byreferringtotheprecedinghighlightedcode.

ThehandlervariableintheargumentsofthejQuery.event.add()methodstoresthefunctionthatwasoriginallypassedasanargumenttothejQuery.fn.on()method.Wecanrefertothisfunctionasourobserverfunction,sinceitisexecutedwhenthe

Page 77: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

appropriateeventfiresontheelementthatitwasattachedto.

Inthefirsthighlightedcodearea,jQuerycreatesandassignsaguidpropertytotheobserverfunctionthatisstoredinthehandlervariable.KeepinmindthatassigningpropertiestofunctionsispossibleinJavaScript,sincefunctionsarefirst-classobjects.ThejQuery.guid++statementisexecutedrightaftertheassignmentoftheoldvalueandisrequiredsincejQuery.guidisapage-widecounterusedbyjQueryandjQuerypluginsinternally.TheguidpropertyontheobserverfunctionisusedasawaytoidentifyandlocatetheobserverfunctioninsidetheobserverlistthatjQueryhasforeachelement.Forexample,itisusedbythejQuery.fn.off()methodtolocateandremoveanobserverfunctionfromtheobserverlistassociatedwithanelement.

TipjQuery.guidisapage-widecounterthatisusedbythepluginsandjQueryitselfasacentralizedwaytoretrieveuniqueintegerIDs.ItisoftenusedtoassignuniqueIDstoelements,objects,andfunctions,inordertomakeiteasiertolocatethemincollections.ItistheresponsibilityofeachimplementerthatretrievesandusesthecurrentvalueofjQuery.guidtoalsoincreasethepropertyvalue(byone)aftereachuse.Otherwise,andsincethisisapage-widecounterthatisusedbybothjQuerypluginsandjQuerythemselvesforidentification,thepagewillprobablyfacemalfunctionsthatarehardtodebug.

Inthesecondandthirdhighlightedcodeareas,jQueryinitializesanarraytoholdtheobserverlistsforeachindividualeventthatmayfireonthatelement.OnethingtonoteinthesecondhighlightedcodeareaisthattheobserverlistsfoundintheelemDatavariablearenotapropertyontheactualDOMelement.AsshowninthedataPriv.get(elem)statement,nearthestartofthejQuery.event.add()method,jQueryusesseparatemappingobjectstoholdtheassociationsbetweenDOMelementsandtheirobserverlists.Byusingthisdatacachemechanism,jQueryisabletoavoidpollutingtheDOMelementswiththeextrapropertiesthatareneededbyitsimplementation.

NoteYoucaneasilylocatethedatacachemechanismimplementationinthesourcecodeofjQuerybysearchingforfunctionData().ThiswillbringyoutotheconstructorfunctionoftheDataclassthatisalsofollowedbytheimplementationoftheclassmethodsthataredefinedintheData.prototypeobject.Formoreinformation,youcanvisithttp://api.jquery.com/data.

ThenexthighlightedcodeareaiswherejQuerycheckswhethertheEventTarget.addEventListener()methodisactuallyavailableforthatelementandthenusesittoaddtheeventlistenertotheelement.Inthefinalhighlightedcodearea,jQueryaddstheobserverfunctiontoitsinternallist,whichholdsalltheobserversofthesameeventtypethatareattachedtothatspecificelement.

NoteDependingontheversionyouareusing,youmightgetdifferentresultstosomedegree.

Page 78: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

ThemostrecentstablejQueryversionreleasedandusedasreferencewhilewritingthisbookwasv2.2.0.

Incaseyouneedtoprovidesupportforolderbrowsers,forexample,InternetExplorerlowerthanversion9,thenyoushouldusethev1.xversionsofjQuery.Thelatestversionasofthewritingofthisbookwasv1.12.0,whichofferstheexactsameAPIasthev2.2.xversions,butalsohastherequiredcodetoworkonolderbrowsers.

Inordertocovertheimplementationinconsistenciesofolderbrowsers,theimplementationofjQuery.event.add()injQueryv1.xisabitlongerandmorecomplex.OneofthereasonsforthisisbecausejQueryalsoneedstotestwhetherEventTarget.addEventListener()isactuallyavailableinthebrowserthatitisrunningandtrytouseEventTarget.attachEvent()ifthisisnotthecase.

Aswesawintheprecedingcode,thejQueryimplementationfollowstheoperationmodelthattheObserverPatterndescribes,butitalsoincorporatessomeimplementationtricksinordertomakeitworkmoreefficientlywiththeAPIsavailabletowebbrowsers.

Thedocument-readyobserverAnotherconvenientmethodthatjQueryoffers,whichiswidelyusedbydevelopers,isthe$.fn.ready()method.ThismethodacceptsafunctionparameterandexecutesitonlyaftertheDOMtreeofthepagehasbeenfullyloaded.Suchathingcanbeusefulincaseyourcodeisnotloadedlastinthepageandyoudon’twanttoblocktheinitialpagerender,ortheelementsthatitneedstomanipulatearedefinedlaterthanitsown<script>tag.

NoteKeepinmindthatthe$.fn.ready()methodworksslightlydifferentlythanthewindow.onloadcallbackandthe“load”eventofthepage,whichwaituntilalltheresourcesofthepageareloaded.Formoreinformation,youcanvisithttp://api.jquery.com/ready.

Thefollowingcodedemonstratesthemostcommonwaytousethe$.fn.ready()method:

$(document).ready(function(){

/*thiscodewillexecuteonlyafterthepagehasbeenfullyloaded*/

})

IfwetrytolocatetheimplementationofjQuery.fn.ready,wewillseethatitactuallyusesjQuery.ready.promiseinternallytowork:

jQuery.fn.ready=function(fn){

//Addthecallback

jQuery.ready.promise().done(fn);

returnthis;

};

/*…alotlinesofcodeinbetween*/

jQuery.ready.promise=function(obj){

if(!readyList){

readyList=jQuery.Deferred();

Page 79: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

//Catchcaseswhere$(document).ready()iscalled

//afterthebrowsereventhasalreadyoccurred.

//Support:IE9-10only

//OlderIEsometimessignals"interactive"toosoon

if(document.readyState==="complete"||(document.readyState!==

"loading"&&!document.documentElement.doScroll)){

//Handleitasynchronouslytoallow…todelayready

window.setTimeout(jQuery.ready);

}else{

//Usethehandyeventcallback

document.addEventListener("DOMContentLoaded",completed);

//Afallbacktowindow.onload,thatwillalwayswork

window.addEventListener("load",completed);

}

}

returnreadyList.promise(obj);

};

Asyoucanseeintheprecedinghighlightedcodeareasoftheimplementation,jQueryusesaddEventListenertoobservewhentheDOMContentLoadedeventisfiredonthedocumentobject.Moreover,toensurethatitwillworkacrossawiderangeofbrowsers,italsoobservesfortheloadeventtobefiredonthewindowobject.

ThejQuerylibraryalsoprovidesshortermethodstoaddtheabovefunctionalityinyourcode.Sincetheaforementionedimplementationdoesnotactuallyneedareferencetothedocument,wecaninsteadjustwrite$().ready(function(){/*...*/}).Therealsoexistsanoverloadofthe$()functionthatachievesthesameresult,whichisusedlike$(function(){/*...*/}).ThesetwoalternativewaystousejQuery.fn.readyhavebeenheavilycriticizedamongdevelopers,sincetheycommonlyleadtomisunderstandings.Thesecond,shorterversioninparticularcanleadtoconfusion,sinceitlookslikeanImmediatelyInvokedFunctionExpression(IIFE),apatternthatJavaScriptdevelopersuseheavilyandhavelearnedtorecognize.Infact,itonlydiffersbyonecharacter($)andasaresult,itsuseisnotsuggestedbeforeadiscussionwiththerestofyourdeveloperteam.

NoteThe$.fn.ready()methodisalsocharacterizedasamethodthatprovidesaneasywaytoimplementtheLazyInitialization/ExecutionPatterninourcode.Thecoreconceptofthispatternistopostponetheexecutionofapieceofcodeorloadaremoteresourceatalaterpointoftime.Forexample,wecanwaitforthepagetobefullyloadeduntilweaddourobserversorwaitforacertaineventtohappenbeforedownloadingawebresource.

Page 80: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

DemonstrateasampleusecaseInordertoseetheObserverPatterninaction,wewillcreateanexampleshowcasingaskeletonimplementationofadashboard.Inourexample,theuserwillbeabletoaddinformationboxestohisdashboardrelatedtosomesampleitemsandcategoriesthatareavailableforselectionontheheader.

Ourexamplewillhavethreepredefinedcategoriesforouritems:Products,Sales,andAdvertisements.Eachofthesecategorieswillhaveaseriesofrelateditemsthatwillappearinthearearightbelowthecategoryselector.Theuserwillbeabletoselectthedesiredcategorybyusingadrop-downselectorandthiswillchangethevisibleselectionitemsofthedashboard.

Ourdashboardwillinitiallycontainahintinformationboxaboutthedashboardusage.Wheneverauserclicksononeofthecategoryitems,anewinformationboxwillappearinourthree-columnlayoutdashboard.Intheprecedingimage,theuserhasaddedtwonewinformationboxesforProductBandProductDbyclickingontheassociatedbuttons.

Page 81: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

Theuserwillalsobeabletodismissanyoftheseinformationboxesbyclickingonaredclosebuttononthetop-rightofeachinformationbox.Intheprecedingimage,theuserdismissedtheProductDinformationbox,thenaddedinformationboxesfortheAdvertisement3andlaterthe1st,2nd,and3rdweekitemsoftheSalescategory.

Byjustreadingtheabovedescription,wecaneasilyisolatealltheuserinteractionsthatarerequiredfortheimplementationofourdashboard.WewillneedtoaddobserversforeachoneoftheseuserinteractionsandwritecodeinsidethecallbackfunctionsthatexecutetheappropriateDOMmanipulations.

Indetail,ourcodewillneedto:

ObservechangesdonetothecurrentlyselectedelementandrespondtosucheventbyhidingorrevealingtheappropriateitemsObservetheclicksoneachitembuttonandrespondbyaddinganewinformationboxObservetheclicksontheclosebuttonofeachinformationboxandrespondbyremovingitfromthepage

Nowlet’sproceedandreviewtheHTML,CSS,andJavaScriptcoderequiredfortheprecedingexample.Let’sstartwiththeHTMLcodeandforreference,let’ssaythatwesaveditinafilenamedDashboardExample.html,asfollows:

<!DOCTYPEhtml>

<html>

<head>

<title>DashboardExample</title>

<linkrel="stylesheet"type="text/css"href="dashboard-example.css">

</head>

<body>

<h1id="pageHeader">DashboardExample</h1>

<divclass="dashboardContainer">

<sectionclass="dashboardCategories">

<selectid="categoriesSelector">

<optionvalue="0"selected>Products</option>

<optionvalue="1">Sales</option>

<optionvalue="2">Advertisements</option>

</select>

<sectionclass="dashboardCategory">

<button>ProductA</button>

<button>ProductB</button>

<button>ProductC</button>

<button>ProductD</button>

<button>ProductE</button>

</section>

<sectionclass="dashboardCategoryhidden">

<button>1stweek</button>

<button>2ndweek</button>

<button>3rdweek</button>

<button>4thweek</button>

</section>

<sectionclass="dashboardCategoryhidden">

<button>Advertisement1</button>

Page 82: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

<button>Advertisement2</button>

<button>Advertisement3</button>

</section>

<divclass="clear"></div>

</section>

<sectionclass="boxContainer">

<divclass="boxsizer">

<articleclass="box">

<headerclass="boxHeader">

Hint!

<buttonclass="boxCloseButton">&#10006;</button>

</header>

Pressthebuttonsabovetoaddinformationboxes…

</article>

</div>

</section>

<divclass="clear"></div>

</div>

<scripttype="text/javascript"src="jquery.js"></script>

<scripttype="text/javascript"src="dashboard-example.js">

</script>

</body>

</html>

IntheprecedingHTML,weplacedallourdashboard-relatedelementsinsidea<div>elementwiththedashboardContainerCSSclass.Thiswillenableustohaveacentricstartingpointtosearchforourdashboard’selementsandalsoscopeourCSS.Insideit,wedefinetwo<section>elementsinordertodividethedashboardintologicalareasusingsomeHTML5semanticelements.

Thefirst<section>withthedashboardCategoriesclassisusedtoholdthecategoriesselectorofourdashboard.Insideit,wehavea<select>elementwiththeIDcategoriesSelectorthatisusedtofilterthevisiblecategoryitemsandthreesubsectionswiththedashboardCategoryclassthatareusedtowrapthe<button>elementsthatwillpopulatethedashboardwithinformationboxeswhenclicked.Twoofthemalsohavethehiddenclasssothatonlythefirstoneisvisiblewhenthepageloadsbymatchingtheinitiallyselectedoption(<option>)ofthecategoryselector.Also,attheendofthefirstsection,wealsoaddeda<div>withtheclearclassthat,aswesawinthefirstchapter,willbeusedtoclearthefloated<button>elements.

Thesecond<section>withtheboxContainerclassisusedtoholdtheinformationboxesofourdashboard.Initially,itcontainsonlyonewithahintabouthowtousethedashboard.Weusea<div>elementwiththeboxsizerclasstosettheboxdimensionsandanHTML5<article>elementwiththeboxclasstoaddtherequiredborderpaddingandshadow,similartotheboxelementsfromthefirstchapter.

Eachinformationbox,besidesitscontent,alsocontainsa<header>elementwiththeboxHeaderclassanda<button>elementwiththeboxCloseButtonclassthat,whenclicked,removestheinformationboxthatcontainsit.Wealsousedthe&#10006;HTMLcharactercodeasthebutton’scontentinordertogetabetter-looking“x”markandavoid

Page 83: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

usingaseparateimageforthatpurpose.

Lastly,sincetheinformationboxesarealsofloated,wealsoneeda<div>withtheclearclassattheendoftheboxContainer.

Inthe<head>oftheprecedingHTML,wealsoreferenceaCSSfilenamedasdashboard-example.csswiththefollowingcontent:

.dashboardCategories{

margin-bottom:10px;

}

.dashboardCategoriesselect,

.dashboardCategoriesbutton{

display:block;

width:200px;

padding:5px3px;

border:1pxsolid#333;

margin:3px5px;

border-radius:3px;

background-color:#FFF;

text-align:center;

box-shadow:01px1px#777;

cursor:pointer;

}

.dashboardCategoriesselect:hover,

.dashboardCategoriesbutton:hover{

background-color:#DDD;

}

.dashboardCategoriesbutton{

float:left;

}

.box{

padding:7px10px;

border:solid1px#333;

margin:5px3px;

box-shadow:01px2px#777;

}

.boxsizer{

float:left;

width:33.33%;

}

.boxHeader{

padding:3px10px;

margin:-7px-10px7px;

background-color:#AAA;

box-shadow:01px1px#999;

}

.boxCloseButton{

float:right;

Page 84: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

height:20px;

width:20px;

padding:0;

border:1pxsolid#000;

border-radius:3px;

background-color:red;

font-weight:bold;

text-align:center;

color:#FFF;

cursor:pointer;

}

.clear{clear:both;}

.hidden{display:none;}

AsyoucanseeinourCSSfile,firstofallweaddsomespacebelowtheelementwiththedashboardCategoriesclassandalsodefinethesamestylingforthe<select>elementandthebuttonsinsideit.Inordertodifferentiateitfromthedefaultbrowserstyling,weaddsomepadding,aborderwithroundedcorners,adifferentbackgroundcolorwhenhoveringthemousepointer,andsomespaceinbetweenthem.Wealsodefinethatour<select>elementshouldbedisplayedaloneinitsrowasablockandthatthecategoryitembuttonsshouldfloatnexttoeachother.WeagainusetheboxsizerandboxCSSclasses,aswedidinChapter1,ARefresheronjQueryandtheCompositePattern;thefirstonetocreateathree-columnlayoutandthesecondonetoactuallyprovidethestylingofaninformationbox.WecontinuebydefiningtheboxHeaderclassthatisappliedtothe<header>elementsofourinformationboxes,anddefinesomepadding,agreybackgroundcolor,alightshadow,andalsosomenegativemarginssothatitcounterbalancestheeffectofthebox’spaddingsandplacesitselfnexttoitsborder.

Tocompletethestylingoftheinformationboxes,wealsodefinetheboxCloseButtonCSSclassthat(i)floatsthebox’sclosebuttonstotheupper-rightcornerinsidethebox<header>,(ii)definesa20pxwidthandheight,(iii)overridesthedefaultbrowser’s<button>stylingtozeropadding,and(iv)addsasingle-pixelblackborderwithroundedcornersandaredbackgroundcolor.Lastly,likeinChapter1,ARefresheronjQueryandtheCompositePatternwedefinetheclearutilityCSSclasstopreventtheelementfrombeingplacednexttothepreviousfloatingelementsandalsodefinethehiddenclassasaconvenientwayofhidingelementsofthepage.

InourHTMLfile,wereferencethejQuerylibraryitselfandalsoaJavaScriptfilenamedasdashboard-example.jsthatcontainsourdashboardimplementation.Followingthebestpracticesofcreatingperformantwebpages,wehaveplacedthemrightbeforethe</body>tag,inordertoavoiddelayingtheinitialpagerendering:

$(document).ready(function(){

$('#categoriesSelector').change(function(){

var$selector=$(this);

varselectedIndex=+$selector.val();

var$dashboardCategories=$('.dashboardCategory');

var$selectedItem=$dashboardCategories.eq(selectedIndex).show();

$dashboardCategories.not($selectedItem).hide();

Page 85: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

});

functionsetupBoxCloseButton($box){

$box.find('.boxCloseButton').click(function(){

$(this).closest('.boxsizer').remove();

});

}

//maketheclosebuttonofthehintboxwork

setupBoxCloseButton($('.box'));

$('.dashboardCategorybutton').on('click',function(){

var$button=$(this);

varboxHtml='<divclass="boxsizer"><articleclass="box">'+

'<headerclass="boxHeader">'+

$button.text()+

'<buttonclass="boxCloseButton">&#10006;'+

'</button>'+

'</header>'+

'Informationboxregarding'+$button.text()+

'</article></div>';

$('.boxContainer').append(boxHtml);

setupBoxCloseButton($('.box:last-child'));

});

});

Wehaveplacedallourcodeinsidea$(document).ready()call,inordertodelayitsexecutionuntiltheDOMtreeofthepageisfullyloaded.Thiswouldbeabsolutelyrequiredifweplacedourcodeinthe<head>element,butitisalsoabestpracticethatisgoodtofollowinanycase.

WefirstaddanobserverforthechangeeventonthecategoriesSelectorelementusingthe`$.fn.change()`method,whichisactuallyashorthandmethodforthe$.fn.on('change',/*…*/)method.InjQuery,thevalueofthethiskeywordinsideafunctionthatisusedasanobserverholdsareferencetotheDOMelementthattheeventwasfired.ThisappliestoalljQuerymethodsthatregisterobservers,fromthecore$.fn.on()tothe$.fn.change()and$.fn.click()convenientmethods.Soweusethe$()functiontomakeajQueryobjectwiththe<select>elementandstoreitinthe$selectorvariable.Then,weuse$selector.val()toretrievethevalueoftheselected<option>andcastittoanumericvaluebyusingthe+operator.Rightafterthis,weretrievethe<section>elementsofdashboardCategoryandcachetheresulttothe$dashboardCategoriesvariable.Then,weproceedbyfindingandrevealingthecategorywhosepositionisequaltothevalueoftheselectedIndexvariableandalsostoretheresultingjQueryobjecttothe$selectedItemvariable.Finally,weareusingthe$selectedItemvariablewiththe$.fn.not()methodtoretrieveandhideallthecategoryelements,exceptfromtheonewejustrevealed.

Inthenextcodesection,wedefinethesetupBoxCloseButtonfunctionthatwillbeusedtoinitializethefunctionalityoftheclosebutton.ItexpectsajQueryobjectwiththeboxelementsasaparameter,andforeachofthem,searchestheirdescendantsforthe

Page 86: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

boxCloseButtonCSSclassthatweuseontheclosebuttons.Using$.fn.click(),whichisaconvenientmethodfor$.fn.on('click',/*fn*/),weregisterananonymousfunctiontobeexecutedwheneveraclickeventisfiredthatusesthe$.fn.closest()methodtofindthefirstancestorelementwiththeboxsizerclassandremovesitfromthepage.Rightafterthis,wecallthisfunctiononcefortheboxelementsthatalreadyexistedinthepageatthetimewhenthepagewasloaded.Inthiscase,theboxelementwiththeusagehint.

NoteAnextrathingtokeepinmindwhenusingthe$.fn.closest()methodisthatitbeginstestingthegivenselectorfromthecurrentelementofthejQuerycollectionbeforeproceedingwithitsancestorelements.Formoreinformation,youcanvisititsdocumentationathttp://api.jquery.com/closest.

Inthefinalcodesection,weusethe$.fn.on()methodtoaddanobserverfortheclickeventoneachofthecategorybuttons.Inthiscase,insidetheanonymousobserverfunction,weusethethiskeyword,whichholdstheDOMelementofthe<button>thatwasclicked,andusethe$()methodtocreateajQueryobjectandcacheitsreferenceinthe$buttonvariable.Rightafterthis,weretrievethebutton’stextcontentusingthe$.fn.text()methodandalongwithit,constructtheHTMLcodefortheinformationbox.Fortheclosebutton,weusethe&#10006HTMLcharactercodethatwillberenderedasaprettier“X”icon.ThetemplatewecreatedisbasedontheHTMLcodeoftheinitiallyvisiblehintbox;fortheneedsofthischapter’sexample,weuseplainstringconcatenation.Lastly,weappendthegeneratedHTMLcodeforourboxtotheboxContainer,andsinceweexpectittobethelastelement,weusethe$()functiontofinditandprovideitasaparametertothesetupBoxCloseButton.

Page 87: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

HowitiscomparedwitheventattributesBeforetheEventTarget.addEventListener()wasdefinedintheDOMLevel2Eventsspecification,theeventlistenerswereregisteredeitherbyusingtheeventattributesthatareavailableforHTMLelementsortheelementeventpropertiesthatareavailableforDOMnodes.

NoteFormoreinformationontheDOMLevel2Eventspecificationandeventattributes,youcanvisithttp://www.w3.org/TR/DOM-Level-2-Eventsandhttps://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Event_attributes,respectively.

TheeventattributesareasetofattributesthatareavailabletoHTMLelementsandprovideadeclarativewayofdefiningpiecesofJavaScriptcode(preferablyfunctioncalls)thatshouldbeexecutedwhenaspecificeventistriggeredonthatelement.Becauseoftheirdeclarativenatureandhowsimplytheycanbeused,thisisoftenthefirstwaythatnewdevelopersgetintroducedtoeventsinwebdevelopment.

Ifweusedeventattributesintheaboveexample,thentheHTMLcodefortheclosebuttonsintheinformationboxeswilllookasfollows:

<articleclass="box">

<headerclass="boxHeader">

Hint!

<buttononclick="closeInfoBox();"

class="boxCloseButton">&#10006;</button>

</header>

Pressthebuttonsabovetoaddinformationboxes…

</article>

Also,weshouldchangethetemplatethatisusedtocreatenewinformationboxesandexposethecloseInfoBoxfunctiononthewindowobject,inorderforittobeaccessiblefromtheHTMLeventattribute:

window.closeInfoBox=function(){

$(this).closest('.boxsizer').remove();

};

SomeofthedisadvantagesofusingeventattributesovertheObserverPatternare:

ItmakesithardertodefinemultipleseparateactionsthathavetobeexecutedwhenaneventfiresonanelementItmakestheHTMLcodeofthepagebiggerandlessreadableItisagainsttheseparationofconcernsprinciple,sinceitaddsJavaScriptcodeinsideourHTML,possiblymakingabughardertotrackandfixMostofthetime,itleadstothefunctionsbeingcalledintheeventattributegettingexposedtotheglobalwindowobject,thereby“polluting”theglobalnamespace

UsingtheelementeventpropertieswouldnotrequireanychangestoourHTML,keepingalltheimplementationinourJavaScriptfiles.Thechangesrequiredinour

Page 88: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

setupBoxCloseButtonfunctionwillmakeitlookasfollows:

functionsetupBoxCloseButton($box){

var$closeButtons=$box.find('.boxCloseButton');

for(vari=0;i<$closeButtons.length;i++){

$closeButtons[i].onclick=function(){

this.onclick=null;

$(this).closest('.boxsizer').remove();

};

}

}

Notethat,forconvenience,wearestillusingjQueryforDOMmanipulations,buttheresultingcodestillhassomeoftheaforementioneddisadvantages.Moreimportantly,inordertoavoidmemoryleaks,wearealsorequiredtoremovethefunctionassignedtotheonclickpropertybeforeremovingtheelementfromthepage,ifitcontainsreferencestotheDOMelementthatitisappliedon.

Usingthetoolsthattoday’sbrowsersoffer,wecanevenmatchtheconveniencethatthedeclarativenatureofeventattributesoffers.Inthefollowingimage,youcanseehowtheFirefoxdevelopertoolsprovideuswithhelpfulfeedbackwhenweusethemtoinspectapageelementthathasaneventlistenerattached:

Asyoucanseeintheprecedingimage,alltheelementsthathaveobserversattachedalsohaveanevsignrightnexttothem,whichwhenclicked,displaysadialogshowingalltheeventlistenersthatarecurrentlyattached.Tomakeourdevelopingexperienceevenbetter,wecandirectlyseethefileandthelinethatthesehandlersweredefinedin.Moreover,wecanclickontheminordertoexpandandrevealtheircode,orclickonthesigninfrontofthemtonavigatetotheirsourceandaddbreakpoints.

OneofthebiggestbenefitsofusingtheObserverPatternovereventattributesisclearlyvisibleinthecasewhereweneedtotakemorethanoneactionwhenacertaineventhappens.Supposethatwealsoneedtoaddanewfeatureinourexampledashboard,whichwouldpreventauserfromaccidentallydouble-clickingacategoryitembuttonandaddingthesameinformationboxtwicetothedashboard.Thenewimplementationshouldideallybecompletelyindependentfromtheexistingone.UsingtheObserverPattern,allweneedtodoisaddthefollowingcodethatobservesforbuttonclicksanddisablesthatbuttonfor700milliseconds:

Page 89: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

$(document).ready(function(){

$('.dashboardCategorybutton').on('click',function(){

var$button=$(this);

$button.prop('disabled',true);

setTimeout(function(){

$button.prop('disabled',false);

},700);

});

});

TheprecedingcodeisindeedcompletelyindependentfromthebasicimplementationandwecouldplaceitinsidethesameoradifferentJSfileandloadittoourpage.Thiswouldbemoredifficultwhenusingeventattributes,sinceitwouldrequireustodefinebothactionsatthesametimeinsidethesameeventhandlerfunction;asaresult,itwouldstronglycouplethetwoindependentactions.

Page 90: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

AvoidmemoryleaksAswesawearlier,therearesomestrongadvantagesofusingtheObserverPatterntohandleeventsonawebpage.WhenusingtheEventTarget.addEventListener()methodtoaddanobservertoanelement,wealsoneedtokeepinmindthatinordertoavoidmemoryleaks,wealsohavetocalltheEventTarget.removeEventListener()methodbeforeremovingsuchelementsfromthepagesothattheobserversarealsoremoved.

NoteFormoreinformationonremovingeventlistenersfromelements,youcanvisithttps://developer.mozilla.org/en-US/docs/Web/API/EventTarget/removeEventListener,orforthejQueryequivalentmethod,visithttp://api.jquery.com/off/.

ThejQuerylibrarydevelopersunderstoodthatsuchanimplementationconcerncouldeasilybeforgottenornothandledproperly,therebymakingtheadoptionoftheObserverPatternlookmorecomplex,sotheydecidedtoencapsulatetheappropriatehandlinginsidethejQuery.eventimplementation.Asaresult,whenusinganyeventhandlingjQuerymethod,suchasthecore$.fn.on()oranyoftheconvenientmethodssuchas$.fn.click()or$.fn.change(),theobserverfunctionsaretrackedbyjQueryitselfandareproperlyunregisteredifwelaterdecidetoremovetheelementfromthepage.AswesawearlierintheimplementationofjQuery.event,jQuerystoresareferencetotheobserversofeachelementinaseparatemappingobject.EverytimeweauseajQuerymethodthatremovesDOMelementsfromthepage,itfirstmakessuretoremoveanyobserversattachedtothoseelementsoranyofthedescendantelements,bycheckingthemappingobject.Asaresult,theexamplecodeweusedearlierisnotcausingmemoryleakseventhoughwearenotusinganymethodthatexplicitlyremovestheobserversweaddtothecreatedelements.

TipBecarefulwhenmixingjQueryandplainDOMmanipulations

EventhoughalljQuerymethodskeepyousafefrommemoryleakscausedfromobserversthatareneverunregistered,keepinminditcan’tprotectyouifyouremoveelementsusingplainmethodsfromtheDOMAPI.IfmethodssuchasElement.remove()andElement.removeChild()areusedandtheremovedelementsortheirdescendantshaveobserversattached,thentheyarenotgoingtobeunregisteredautomatically.ThesameapplieswhenassigningtotheElement.innerHTMLproperty.

Page 91: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 92: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

IntroducingtheDelegatedEventObserverPatternNowthatwehavelearnedsomeadvanceddetailsabouthowtousetheObserverPatternusingjQuery,wewillgetintroducedtoaspecialvariationofitthatfitsperfectlytothewebplatformandprovidessomeextrabenefits.TheDelegatedEventObserverPattern(orsimplyDelegateObserverPattern)isoftenusedinwebdevelopmentanditutilizesthebubblingfeaturethatmosteventsthatarefiredonDOMelementshave.Forexample,whenweclickonapageelement,theclickeventisimmediatelyfiredonit,andrightafterthisitalsofiresonallitsparentelementsuntilitreachestherootofourHTMLdocument.UsingaslightlydifferentoverloadedversionofthejQuery’s$.fn.onmethod,wecaneasilycreateandattachobserversonpageelementsfordelegatedeventsthatarefiredonspecificchildelements.

NoteTheterm“EventDelegation”describestheprogrammingpatternwherethehandlerofaneventisnotattacheddirectlytotheelementofinterest,butisinsteadattachedtooneofitsancestorelements.

Page 93: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

HowitsimplifiesourcodeReimplementingourdashboardexampleusingtheDelegatedEventObserverPatternwillrequireustochangeonlythecodeoftheincludedJavaScriptfiletothefollowing:

$(document).ready(function(){

$('#categoriesSelector').change(function(){

var$selector=$(this);

varselectedIndex=+$selector.val();

var$dashboardCategories=$('.dashboardCategory');

var$selectedItem=$dashboardCategories.eq(selectedIndex).show();

$dashboardCategories.not($selectedItem).hide();

});

$('.dashboardCategories').on('click','button',function(){

var$button=$(this);

varboxHtml='<divclass="boxsizer"><articleclass="box">'+

'<headerclass="boxHeader">'+

$button.text()+

'<buttonclass="boxCloseButton">&#10006;'+

'</button>'+

'</header>'+

'Informationboxregarding'+$button.text()+

'</article></div>';

$('.boxContainer').append(boxHtml);

});

$('.boxContainer').on('click','.boxCloseButton',function(){

$(this).closest('.boxsizer').remove();

});

});

Themostobviousdifferenceisthatthenewimplementationisshorter.Thebenefitscomebydefiningjustoneobservertoacommonancestorelement,foreachactionthatappliestomorethanonepageelement.Forthisreason,weusethe$.fn.on(events,selector,handler)overloadvariationofthe$.fn.on()method.

Specifically,weaddanobservertothepageelementwiththedashboardCategoriesCSSclassandlistenfortheclickeventsthatoriginatefromanyofits<button>descendants.Similarly,weaddasingleobservertotheboxContainerelementthatwillbeexecutedwheneveraclickeventfiresonanyofitsdescendantsthatmatchthe.boxCloseButtonCSSselector.

Sincetheaboveobserversapplynotonlytotheelementsthatexistedinthepageatthemomenttheywereregistered,butalsotoanyelementthatisaddedatanylaterpointoftimeandmatchesthespecifiedCSSselector;weareabletodecouplethecodethathandlestheclicksontheclosebuttonsandplaceitinaseparateobserver,insteadofregisteringanewoneeverytimeanewinformationboxisadded.Asaresult,theobserverthataddsthenewinformationboxesinthedashboardissimplerandonlyhastodealwithcreatingtheHTMLoftheboxandinsertitintothedashboard,leadingtoagreaterseparationof

Page 94: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

concerns.Moreover,wenolongerneedtohandletheregistrationoftheobserverfortheclosebuttonofthehintboxinaseparatepieceofcode.

Page 95: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

ComparethememoryusagebenefitsWewillnowcomparethedifferenceinmemoryusagewhenusingthe$.fn.on()methodwiththesimpleandDelegatedEventObserverPatternvariation.ToachievethiswewillopenthetwoimplementationsofourdashboardexampleandcomparetheirmemoryusageonChrome.ToopenChrome’sdevelopertools,justpressF12andthennavigatetotheTimelinetab.Wepressthe“record”buttonintheChrome’sTimelinetabandthenpresseachcategoryitembutton10times,resultingintheadditionof120informationboxestoourdashboard.Afteraddingalltheboxes,weendupwith121openboxesintotal,sincethehintboxwillstillbeopenandthenstopthetimelinerecording.

TheresultsinthetimelineforourinitialObserverPatternimplementationwilllookasfollows:

RepeatingthesameprocessfortheDelegatedEventObserverPatternimplementationwillgiveasmoothertimeline,revealinglessobjectallocationsandGarbageCollections,asfollows:

Asyoucanseeintheprecedingimages,weendupwith1192pageelementsinbothcases,butinthefirstimplementationweareusing134eventlisteners,ascomparedtotheimplementationwitheventdelegationwhereweinitiallycreatedthreeeventlistenersandneveractuallyaddedanother.

Finally,asyoucanseefromthebluelineinthegraph,thememoryconsumptionofthedelegateversionstayedrelativelythesame,addinguptojustaround200KB.Ontheotherhand,intheoriginalimplementation,theheapsizeincreasedmorethanfivetimes,gainingmorethan1MBofincrease.

Addingsomanyelementsmaynotbeanactualusecase,butthedashboardwillprobablynotbetheonlydynamicpartofyourpage.Asaresult,inarelativelycomplexwebpage,wecouldgetsimilarimprovementsifwereimplementedeveryapplicablepartofitusing

Page 96: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

theDelegatedEventObserverPatternvariant.

Page 97: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 98: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

SummaryInthischapter,welearnedabouttheObserverPattern,howitcanmaketheHTMLcodeofourwebpagescleaner,andthewaythatdecouplesitfromourapplication’scode.WelearnedhowjQueryaddsaprotectionlayertoitsmethodsinordertoprotectusfromundetectedmemoryleaks,whichmayoccurbyaddingobserverstoelements,whennotusingthejQueryDOMmanipulationmethods.

WealsotriedtheDelegatedEventObserverPatternvariantandusedittorewriteourinitialexample.Wecomparedthetwoimplementationsandsawhowitsimplifieswritingcodethatappliestomanypageelementswhentheyaregeneratedafterthepagehasbeenloaded.Finally,wehadacomparisonregardingthememoryconsumptionoftheplainObserverPatternwithitsdelegatevariantandhighlightedhowitalsolessensthememoryconsumptionofourpagebyreducingtherequirednumberofattachedobservers.

NowthatwehavecompletedourintroductiononhowtheObserverPatternisusedtolistentouseractions,wecanmoveontothenextchapterwherewewilllearnaboutcustomeventsandthePublish/SubscribePatternandthewaytheycanleadtoamoredecoupledimplementation.

Page 99: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 100: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

Chapter3.ThePublish/SubscribePatternInthischapter,wewillshowcasethePublish/SubscribePattern,adesignpatternquitesimilartotheObserverPatternbutwithamoredistinctrolethatisabetterfitformorecomplexusecases.WewillseehowitdiffersfromtheObserverPatternandhowjQueryadoptedsomeofitsconceptsandbroughtthemtoitsObserverPatternimplementation.

Later,wewillproceedandrewriteourpreviouschapter’sexampleusingthispattern.Wewillusethispattern’sbenefitstoaddsomeextrafeaturesandalsoreducethecouplingofourcodewiththeelementsofthewebpage.

Inthischapter,wewill:

IntroducethePublish/SubscribePatternLearnhowitdiffersandwhatadvantagesithasovertheObserverPatternLearnhowjQuerybringssomeofitsfeaturestoitsmethodsLearnhowtoemitcustomeventswithjQueryRewriteandextendtheexamplefromChapter2,TheObserverPattern,usingthispattern

Page 101: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

IntroducingthePublish/SubscribePatternThePublish/SubscribePatternisaMessagingPatternwheretheemittersofthemessages,calledthepublishers,multicastmessagestoanumberofrecipients,calledthesubscribers,thathaveexpressedtheirinterestinreceivingsuchmessages.Thekeyconceptofthispattern,whichisalsocommonlyreferredtoasthePub/SubPatterninshort,istoprovideawaytoavoiddependenciesbetweenthepublishersandtheirsubscribers.

Anextraconceptofthispatternistheuseoftopicsthatareusedbythesubscribersinordertoexpressthattheyareonlyinterestedinmessagesofaspecifictype.Thisway,publishersfiltersubscribersbeforesendingamessageanddistributethatmessageonlytotheappropriateones,therebyreducingtheamountoftrafficandworkrequiredonbothsides.

Anothercommonvariantistouseacentral,application-wideobject,knownasthebroker,thatrelaysmessagesproducedbythepublisherstotherelevantsubscribers.Thebroker,inthiscase,actsasawell-knownmessagehandlertosendandsubscribetomessagetopics.Thisenablesus,insteadofcouplingdifferentapplicationpartstogether,toonlyreferencethebrokeritselfandalsothetopicthatourcomponentsareinterestedin.Eventhoughtopicsmightnotbeanabsoluterequirementinthefirstvariantofthispattern,thisvariantplaysanessentialroleinscalabilitysincetherewillcommonlyexistwaylessbrokers(ifnotjustone)thanpublishersandsubscribers.

Page 102: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

Byfollowingasubscriptionscheme,thecodeofthepublisheriscompletelydecoupledfromthesubscribers,meaningthatthepublisherdoesnothavetoknowtheobjectsdependonthem.Asaresult,wedonotneedtohardcodetothepublishereachseparateactionthatshouldbeexecutedonthedifferentpartsofourapplication.Instead,thecomponentsofanapplication,andpossiblythird-partyextensions,subscribetobenotifiedonlyabouttopics/eventsthattheyneedtoknow.Insuchdistributedarchitecture,addinganewfeaturetoanexistingapplicationrequiresminimaltonochangestotheapplicationcomponentsitdependson.

Page 103: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

HowitdiffersfromtheObserverPatternThemostbasicdifferenceisthat,bydefinition,thePub/SubPatternisaone-way-MessagingPatternthatcanalsopassamessage,unliketheObserverPatternthatjustdescribeshowtonotifytheobserversaboutaspecificstatechangeonthesubject.

Moreover,unliketheObserverPattern,thePub/SubPatternwithabrokerresultsinmorelooselycoupledcodeforthedifferentpartsofanimplementation.Thisisbecausetheobserversneedtoknowtheirsubjectthatisemittingtheevents;however,ontheotherhand,thepublishersandtheirsubscribersonlyneedtoknowthebrokerthatisused.

Page 104: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 105: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

HowitisadoptedbyjQueryOnceagain,thejQuerylibraryprovidesuswithaconvenientwaytotakeadvantageofthePub/SubPatterninourcode.InsteadofextendingitsAPIbyaddingnewmethodsspecificallynamed“publish”and“subscribe”andintroducingnewconcepts,thedevelopersdecidedtoextendthejQuery.fn.on()andjQuery.fn.trigger()methodswiththeabilitytohandleandemitcustomevents.Thisway,jQuerycanbeusedtoimplementapublisher/subscribercommunicationschemeusingthealreadyknownconvenientmethodsitprovides.

Page 106: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

CustomeventsinjQueryCustomeventsallowustousealmostanyuser-definedstringvalueasacommoneventthatwecanaddlistenersfor,andalsomanuallyfireitonpageelements.Asanextrabutapreciousfeature,customeventscanalsocarrysomeextradatatobedeliveredtothelistenersoftheevent.

ThejQuerylibraryaddeditsowncustomeventsimplementation,beforeitwasactuallyaddedtoanywebspecification.Thisway,itwasprovedhowusefultheycanbewhenusedinwebdevelopment.Aswesawinthepreviouschapter,injQuery,thereisaspecificpartoftheimplementationthathandlesboththecommonelementeventandalsocustomevents.ThejQuery.eventobjectholdsalltheinternalimplementationsrelatedtofiringandlisteningtoevents.Also,thejQuery.EventclassisadedicatedwrapperthatjQueryusesfortheneedsofboththecommonelementeventsanditscustomeventsimplementation.

Page 107: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

ImplementingaPub/SubschemeusingcustomeventsInthepreviouschapter,wesawhowthejQuery.fn.on()methodcanbeusedtoaddeventlistenersonelements.Wealsosawthatitsimplementationismaintaininglistswiththeaddedhandlersandnotifyingthemwhenrequired.Moreover,theeventnameseemstohavethesamecoordinationpurpose,justlikethetopic.ThisimplementationsemanticsseemtomatchexactlywiththePub/SubPatternaswell.

ThejQuery.fn.trigger()methodactuallyusestheinternaljQuery.event.trigger()methodthatisusedtofireeventsinjQuery.Ititeratesovertheinternalhandlerslistandexecutesthemwiththerequestedeventalongwithanyextraparametersthatthecustomeventdefines.Onceagain,thisalsomatchestheoperationrequirementsofthePub/SubPattern.

Asaresult,jQuery.fn.trigger()andjQuery.fn.on()seemtomatchtheneedsofthePub/SubPatternandcanbeusedinsteadofseparate“publish”and“subscribe”methods,respectively.SincetheyarebothavailableonthejQuery.fnobject,wecanusethesemethodsonanyjQueryobject.ThisjQueryobjectwillactasanintermediateentitybetweenthepublishersandthesubscribers,inawaythatperfectlyalignswiththedefinitionofthebroker.

Agoodcommonpractice,whichisalsousedbyalotofjQueryplugins,istousetheoutermostpageelementthatholdstheimplementationoftheapplicationorthepluginasthebroker.Ontheotherhand,jQueryactuallyallowsustouseanyobjectasabroker,sinceallthatitactuallyneedsisatargettoemitanobserveforourcustomevents.Asaresult,wecouldevenuseanemptyobjectasourbrokersuchas$({}),incaseusingapageelementseemstoorestrictingornotcleanenoughaccordingtothePub/SubPattern.ThisisactuallywhatthejQueryTinyPub/Sublibrarydoes,alongwithsomemethodaliasing,sothatweactuallyusemethodsnamed“publish”and“subscribe”insteadofjQuery’s“on”and“trigger”.FormoreinformationonTiny,youcanvisititsrepositorypageathttps://github.com/cowboy/jquery-tiny-pubsub.

Page 108: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 109: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

DemonstratingasampleusecaseInordertoseehowthePub/SubPatternisused,andmakeiteasytocompareitwiththeObserverPattern,wearegoingtorewritethedashboardexamplefromChapter2,TheObserverPattern,usingthispattern.Thiswillalsoclearlydemonstratehowthispatterncanhelpusdecoupletheindividualpartsofanimplementationandmakeitmoreextendableandscalable.

Page 110: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

UsingPub/SubonthedashboardexampleFortheneedsofthisdemonstration,wewillusetheHTMLandCSSfilesexactlyaswesawtheminChapter2,TheObserverPattern.

Toapplythispattern,wewillonlyneedtochangethecodeintheJavaScriptfilewithournewimplementation.Inthefollowingcodesnippet,wecanseehowthecodewaschangedinordertoadapttothePublisher/SubscriberPattern:

$(document).ready(function(){

window.broker=$('.dashboardContainer');

$('#categoriesSelector').change(function(){

var$selector=$(this);

varmessage={categoryID:$selector.val()};

broker.trigger('dashboardCategorySelect',[message]);

});

broker.on('dashboardCategorySelect',function(event,message){

var$dashboardCategories=$('.dashboardCategory');

varselectedIndex=+message.categoryID;

var$selectedItem=$dashboardCategories.eq(selectedIndex).show();

$dashboardCategories.not($selectedItem).hide();

});

$('.dashboardCategory').on('click','button',function(){

var$button=$(this);

varmessage={categoryName:$button.text()};

broker.trigger('categoryItemOpen',[message]);

});

broker.on('categoryItemOpen',function(event,message){

varboxHtml='<divclass="boxsizer"><articleclass="box">'+

'<headerclass="boxHeader">'+

message.categoryName+

'<buttonclass="boxCloseButton">&#10006;'+

'</button>'+

'</header>'+

Page 111: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

'Informationboxregarding'+message.categoryName+

'</article></div>';

$('.boxContainer').append(boxHtml);

});

$('.boxContainer').on('click','.boxCloseButton',function(){

varboxIndex=$(this).closest('.boxsizer').index();

varmessage={boxIndex:boxIndex};

broker.trigger('categoryItemClose',[message]);

});

broker.on('categoryItemClose',function(event,message){

$('.boxContainer.boxsizer').eq(message.boxIndex).remove();

});

});

Justlikeinourpreviousimplementation,weuse$(document).ready()inordertodelaytheexecutionofourcodeuntilthepagehasbeenfullyloaded.Firstofall,wedeclareourbrokerandassignittoanewvariableonthewindowobjectsothatitisgloballyavailableonthepage.Forourapplication’sbroker,weareusingajQueryobjectwiththeoutermostcontainerofourimplementation,whichinourcaseisthe<div>elementwiththedashboardContainerclass.

TipEventhoughusingglobalvariablesisgenerallyananti-pattern,westorethebrokerintoaglobalvariablesinceitisanimportantsynchronizationpointofthewholeapplicationandmustbeavailableforeverypieceofourimplementation,eventothosethatarestoredinseparate.jsfiles.AswewilldiscussinthenextchapterabouttheModulePattern,theprecedingcodecouldbeimprovedbystoringthebrokerasapropertyoftheapplication’snamespace.

Inordertoimplementthecategoryselector,wearefirstobservingthe<select>elementforthechangeevent.Whentheselectedcategorychanges,wecreateourmessageusingaplainJavaScriptobjectwiththevalueoftheselected<option>storedinthecategoryIDproperty.Then,wepublishitinthedashboardCategorySelecttopicusingthejQueryjQuery.fn.trigger()methodonourbroker.Thisway,wemovefromaUIelementeventtoamessagewithapplicationsemanticsthatcontainsalltherequiredinformation.Rightbelow,inoursubscriber’scode,weareusingthejQuery.fn.on()methodonourbrokerwiththedashboardCategorySelecttopicasaparameter(ourcustomevent),justlikewewoulddotolistenforasimpleDOMevent.ThesubscriberthenusesthecategoryIDfromthereceivedmessage,justlikewedidintheimplementationofthepreviouschapter,todisplaytheappropriatecategoryitems.

Followingthesameapproach,wesplitthecodethathandlesaddingandclosinginformationboxesinourdashboardinpublishersandsubscribers.Fortheneedsofthisdemonstration,themessageofthecategoryItemOpentopiccontainsjustthenameofthecategorywewanttoopen.However,inanapplicationwheretheboxcontentisretrievedfromaserver,wewouldprobablyuseacategoryitemIDinstead.Thesubscriberthenusesthecategoryitemnamefromthemessagetocreateandinserttherequestedinformation

Page 112: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

box.

Similarly,themessageforthecategoryItemClosetopiccontainstheindexoftheboxthatwewantremoved.OurpublisherusesthejQuery.fn.closest()methodtotraversetheDOMandreachthechildelementsofourboxContainerelementandthenusesthejQuery.fn.index()methodtofinditspositionamongitssiblings.ThesubscriberthenusesjQuery.fn.eq()andtheboxIndexpropertyfromthereceivedmessagetofilterandremoveonlytherequestedinformationboxfromthedashboard.

TipInamorecomplexapplication,insteadoftheboxindex,wecanassociateeachinformationboxelementwithanewlyretrievedjQuery.guidusingamappingobject.Thiswillallowourpublishertousethatguidinthemessageinsteadofthe(DOM-related)elementindex.Thesubscriberwillthensearchthemappingobjectforthatguidinordertolocateandremovetheappropriatebox.

SincewearetryingtodemonstratetheadvantagesofthePub/SubPattern,thisimplementationchangewasnotintroducedinordertoeasethecomparisonwiththeObserverPatternandisinsteadleftasarecommendedexerciseforthereader.

Tosummarizetheabove,weusedthedashboardCategorySelect,categoryItemOpen,andcategoryItemClosetopicsasourapplication-leveleventsinordertodecouplethehandlingoftheuseractionsfromtheirorigin(theUIelement).Asaresult,wenowhavededicatedreusablepiecesofcodethatmanipulateourdashboard’scontent,whichisequivalenttoabstractingthemintoseparatefunctions.Thisallowsustoprogrammaticallypublishaseriesofmessagessothatwecan,forexample,removealltheexistinginformationboxesandaddallthecategoryitemsofthecurrentlyselectedcategory.Alternatively,evenbetter,makethedashboardshowalltheitemsofeachcategoryfor10secondsandthenmovetothenextone.

Page 113: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

ExtendingtheimplementationInordertodemonstratethescalabilitythatthePub/SubPatternbringswithit,wewillextendourcurrentexamplebyaddingacounterwiththenumberofboxesthatarecurrentlyopeninthedashboard.

Forthecounterimplementation,wewillneedtoaddsomeextraHTMLtoourpageandalsocreateandreferenceanewJavaScriptfiletoholdthecounterimplementation:

...

</section>

<divstyle="margin-left:5px;">

Openboxes:

<outputid="dashboardItemCounter">1</output>

</div>

<sectionclass="boxContainer">

...

IntheHTMLpageoftheexample,wewillneedtoaddanextra<div>elementtoholdourcounterandsomedescriptiontext.Forourcounter,weareusingan<output>element,whichisasemanticHTML5elementidealtopresentresultsofuseractions.Thebrowserwilluseitjustlikeanormal<span>element,soitwillappearrightnexttoitsdescription.Also,sincethereisinitiallyahintboxopeninourdashboard,weusea1foritsinitialcontent:

$(document).ready(function(){

broker.on('categoryItemOpencategoryItemClose',function(event,

message){

var$counter=$('#dashboardItemCounter');

varcount=parseInt($counter.text());

if(event.type==='categoryItemOpen'){

$counter.text(count+1);

}elseif(event.type==='categoryItemClose'&&count>0){

$counter.text(count-1);

}

});

});

Page 114: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

Forthecounterimplementationitself,allweneedtodoisaddanextrasubscribertothedashboard’sbroker,whichisgloballyavailabletootherJavaScriptfilesloadedinthepage,sincewehaveattachedittothewindowobject.Wearesimultaneouslysubscribingtotwotopics,bypassingthemspacedelimitedtothejQuery.fn.on()method.Rightafterthis,welocatethecounter<output>elementthathastheIDdashboardItemCounterandparseitstextcontentasanumber.Inordertodifferentiateouraction,basedonthetopicthatthemessagehasreceived,weusetheeventobjectthatjQuerypassesasthefirstparametertoouranonymousfunction,whichisoursubscriber.Specifically,weusethetypepropertyoftheeventobjectthatholdsthetopicnameofthemessagethatwasreceivedandbasedonitsvalue,wechangethecontentofthecounter.

NoteFormoreinformationontheeventobjectthatjQueryprovides,youcanvisithttp://api.jquery.com/category/events/event-object/.

Similarly,wecouldalsorewritethecodethatpreventsaccidentaldouble-clicksonthecategoryitembuttons.AllthatisneededistoaddanextrasubscriberforthecategoryItemOpentopicandusethecategoryNamepropertyofthemessagetolocatethepressedbutton.

Page 115: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

UsinganyobjectasabrokerWhileinourexampleweusedtheoutermostcontainerelementofourdashboardforourbroker,itisalsocommontousethe$(document)objectasabroker.Usingtheapplication’scontainerelementisconsideredagoodsemanticpractice,whichalsoscopestheemittedevents.

Aswedescribedearlierinthischapter,jQueryactuallyallowsustouseanyobjectasabroker,evenanemptyone.Asaresult,wecouldinsteadusesomethingsuchaswindow.broker=$({});forourbroker,incasewepreferitoverusingapageelement.

Byusingnewlyconstructedemptyobjects,wecanalsoeasilycreateseveralbrokers,incasesuchathingwouldbepreferredforaspecificimplementation.Moreover,incaseacentralizedbrokerisnotpreferred,wecouldjustmakeeachpublisherthebrokerofitself,leadingtoanimplementationmorelikethefirst/basicvariantofthePub/SubPattern.

Sinceinmostcases,adeclaredvariableisusedtoaccesstheapplication’sbrokerwithinapage,thereislittledifferencebetweentheaboveapproaches.Justchoosetheonethatbettermatchesyourteam’staste,andincaseyouchangeyourmindatalaterpoint,allyouhavetodoisuseadifferentassignmentonyourbrokervariable.

Page 116: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 117: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

UsingcustomeventnamespacingAsaclosingnoteforthischapter,wewillpresent,inshort,themechanismthatjQueryprovidesfornamespacingcustomevents.Themainbenefitofeventnamespacingisthatitallowsustousemorespecificeventnamesthatbetterdescribetheirpurpose,whilealsohelpingustoavoidconflictsbetweendifferentimplementationpartsandplugins.Italsoprovidesaconvenientwaytounbindalltheeventsofagivennamespacefromanytarget(elementorbroker).

Asimpleexampleimplementationwilllookasfollows:

varbroker=$({});

broker.on('close.dialog',function(event,message){

console.log(event.type,event.namespace);

});

broker.trigger('close.dialog',['messageEmitted']);

broker.off('.dialog');

//removesalleventhandlersofthe"dialog"namespace

Formoreinformation,youcanvisitthedocumentationpageathttp://docs.jquery.com/Namespaced_Eventsandthearticleathttps://css-tricks.com/namespaced-events-jquery/fromtheCSS-Trickswebsite.

Page 118: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 119: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

SummaryInthischapter,wewereintroducedtothePublish/SubscribePattern.WesawitssimilaritieswiththeObserverPatternandalsolearneditsbenefitsbydoingacomparisonofthetwo.WeanalyzedhowthemoredistinctrolesandtheextrafeaturesthatthePublish/SubscribePatternoffersmakeitanidealpatternformorecomplexusecases.WesawhowjQuerydevelopersadoptedsomeofitsconceptsandbroughtthemtotheirObserverPatternimplementationascustomevents.Finally,werewrotetheexamplefromthepreviouschapterusingthePublish/SubscribePattern,addingsomeextrafeaturesandalsoachievinggreaterdecouplingbetweenthedifferentpartsandpageelementsofourapplication.

NowthatwehavecompletedourintroductiontohowthePublish/SubscribePatterncanbeusedasafirststeptodecouplethedifferentpartsofanimplementation,wecanmoveontothenextchapterwherewewillbeintroducedtotheModulePattern.Inthenextchapter,wewilllearnhowtoseparatethedifferentpartsofanimplementationintoindependentmodulesandhowtousenamespacingtoachievebettercodeorganizationanddefineastrictAPItoachievecommunicationbetweenthedifferentmodules.

Page 120: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 121: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

Chapter4.DivideandConquerwiththeModulePatternInthischapter,wewillbeintroducedtotheconceptsofModulesandNamespacingandseehowtheycanleadtomorerobustimplementations.Wewillshowcasehowthesedesignprinciplescanbeusedinapplications,bydemonstratingsomeofthemostcommonlyuseddevelopmentpatternstocreateModulesinJavaScript.

Inthischapter,wewill:

ReviewtheconceptofModulesandNamespacingIntroducetheObjectLiteralPatternIntroducetheModulePatternanditsvariantsIntroducetheRevealingModulePatternanditsvariantsHaveasmalldiveintoES5StrictModeandES6ModulesExplainhowModulescanbeusedandbenefitjQueryapplications

Page 122: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

ModulesandNamespacesThetwomainpracticesofthischapterareModulesandNamespaces,whichareusedtogetherinordertostructureandorganizeourcode.WewillfirstanalyzethemainconceptofModulesthatiscodeencapsulationandrightafterthis,wewillproceedtoNamespacing,whichisusedtologicallyorganizeanimplementation.

Page 123: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

EncapsulatinginternalpartsofanimplementationWhiledevelopingalarge-scaleandcomplexwebapplication,theneedforawell-defined,structuredarchitecturebecomesclearfromthebeginning.Inordertoavoidcreatingaspaghetticodeimplementation,wheredifferentpartsofourcodecalleachotherinachaoticway,wehavetosplitourapplicationintosmall,self-containedparts.

Theseself-containedpiecesofcodecanbedefinedasModules.Todocumentthisarchitectureprinciple,ComputerSciencehasdefinedconceptssuchasSeparationofConcerns,wheretherole,operation,andtheexposedAPIofeachModuleshouldbestrictlydefinedandfocusedonprovidingagenericsolutiontoaspecificproblem.

NoteFormoreinformationonEncapsulationandSeparationofConcerns,youcanvisithttps://developer.mozilla.org/en-US/docs/Glossary/Encapsulationandhttp://aspiringcraftsman.com/2008/01/03/art-of-separation-of-concerns/.

Page 124: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

AvoidingglobalvariableswithNamespacesInJavaScript,thewindowobjectisalsoknownastheGlobalNamespace,whereeachdeclaredvariableandfunctionidentifierisattachedbydefault.ANamespacecanbedefinedasanamingcontextwhereeachidentifierhastobeunique.ThemainconceptofNamespacingistoprovideawaytologicallygroupalltherelatedpiecesofadistinctandself-containedpartofanapplication.Inotherwords,itsuggeststhatwecreategroupswithrelatedfunctionsandvariablesandmakethemaccessibleunderthesameumbrellaidentifier.ThishelpstoavoidnamingcollisionsbetweendifferentpartsofanapplicationandotherJavaScriptlibrariesthatareused,sinceweonlyneedtokeepalltheidentifiersuniqueundereachdifferentNamespace.

AgoodexampleofNamespacingisthemathematicalfunctionsandconstantsthatJavaScriptprovides,whicharegroupedunderthebuilt-inJavaScriptobjectcalledMath.SinceJavaScriptprovidesmorethan40short-namedmathematicalidentifiers,suchasE,PI,andfloor(),inordertoavoidnamingconflictsandgroupingthemtogether,itwasdesignedtomakethemaccessibleaspropertiesoftheMathobjectthatactsastheNamespaceofthisbuilt-inlibrary.

WithoutproperNamespacing,eachfunctionandvariableneedstobeuniquelynamedthroughtheentireapplication,andcollisionscouldhappenbetweentheidentifiersofdifferentapplicationpartsorevenwiththoseofathird-partylibrarythatanapplicationuses.Finally,whileModulesprovideawaytoisolateeachindependentpartofyourapplication,NamespacingprovidesawaytostructureyourdifferentModulestowhatbecomesthearchitectureoftheapplication.

Page 125: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

ThebenefitsofthesepatternsDesigninganapplicationarchitecturebasedonModulesandnamespacingleadstobettercodeorganizationandclearlyseparatedparts.Insucharchitectures,Modulesareusedtogrouptogetherpartsoftheimplementationthatarerelated,whileNamespacesconnectthemtoeachothertocreatetheapplicationstructure.

Thisarchitecturehelpstocoordinatelargedeveloperteams,enablingtheimplementationofindependentpartstotakeplaceinparallel.Itcanalsoshortenthedevelopmenttimeneededtoaddanewfunctionalitytotheexistingimplementation.Thisisbecausetheexistingpiecesthatareusedcanbelocatedeasilyandtheaddedimplementationhaslesschanceofconflictingwiththeexistingcode.

Theresultingcodestructuresarenotonlycleanlyseparated,butsinceeachModuleisdesignedtoachieveasinglegoal,thereisagoodchancethatitcanalsobeusedinothersimilarapplications.Asanaddedbenefit,sincetheroleofeachModuleisstrictlydefined,italsomakestracingtheoriginofabugaloteasierinalargecodebase.

Page 126: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

ThewideacceptanceBoththecommunityandtheenterpriseworldrealizedthat,inordertohavemaintainable,largefrontendapplicationswritteninJavaScript,theyshouldendupwithasetofbestpracticesthatshouldbeincorporatedineverypartoftheirimplementations.

TheacceptanceandadoptionofModulesandNamespacinginJavaScriptimplementationsisclearlyvisibleinthebestpracticesandcodingstyleguidesthatthecommunityandenterpriseshavereleased.

Forexample,Google’sJavaScriptStyleGuide(availableathttps://google.github.io/styleguide/javascriptguide.xml#Naming)describesandsuggestsadoptingnamespacinginourimplementations:

ALWAYSprefixidentifiersintheglobalscopewithauniquepseudonamespacerelatedtotheprojectorlibrary.

Moreover,thejQueryJavaScriptStyleGuide(availableathttps://contribute.jquery.org/style-guide/js/#global-variables)suggestsusingglobalvariablessothat:

Eachprojectmayexposeatmostoneglobalvariable.

Anotherexampleofacceptanceamongthedevelopercommunity,comesfromtheMozillaDeveloperNetwork.Itsguideforobject-orientedJavaScript(availableathttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Introduction_to_Object-Oriented_JavaScript#Namespace)alsosuggestsusingNamespaces,towraptheimplementationofourapplicationunderasingleexposedvariable,usingsomethingassimpleasfollows:

//globalnamespace

varMYAPP=MYAPP||{};

Page 127: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 128: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

TheObjectLiteralPatternTheObjectLiteralPatternisprobablythesimplestwaytowrapalltherelatedpartsofanimplementationunderanumbrellaobjectthatworksasaModule.Thenameofthispatternaccuratelydescribesthewayitisused.ThedeveloperjustneedstodeclareavariableandassignanobjectwithalltherelatedpartsthatneedtobeencapsulatedintothisModule.

Let’sseehowwecancreateaModulethatprovidesuniqueintegerstoapage,inasimilarwayhowjquery.guiddoesit:

varsimpleguid={

guid:1,

init:function(){

this.guid=1;

},

increaseCounter:function(){

this.guid++;

//orsimpleguid.guid++;

},

getNext:function(){

varnextGuid=this.guid;

this.increaseCounter();

returnnextGuid;

}

};

Asseenabove,asimplerulethatyoucanfollowinordertoadoptthispatternistodefineallthevariablesandfunctionsthateachimplementationneedsaspropertiesofanobject.OurcodeisreusableanddoesnotpollutetheGlobalNamespace,otherthanjustdefiningasinglevariablenameforourModule,simpleguidinthiscase.

WecanaccesstheModulepropertiesinternally,eitherbyusingthethiskeyword,suchasthis.guid,orusingthefullnameoftheModulesuchassimpleguid.guid.InordertousetheaboveModuleinourcode,wejustneedtoaccessitspropertybyusingitsname.Forexample,callingthesimpleguid.getNext()methodwillreturntoourcodethenext-in-ordernumericguidandalsochangetheModule’sstatebyincreasingtheinternalcounter.

OneofthenegativesofthispatternisthatitdoesnotprovideanyprivacytotheinternalpartsoftheModule.AlltheinternalpartsoftheModulecanbeaccessedandbeoverriddenbyexternalcode,eventhoughweideallyprefertoonlyexposethesimpleguid.init()andsimpleguid.getNext()methods.Thereareseveralnamingconventionsthatdescribeprependingorappendinganunderscore(_)tothenamesofpropertiesthatareintendedonlyforinternaluse,butthistechnicallydoesn’tfixthisdisadvantage.

AnotherdisadvantageisthatwritingabigModuleusinganobjectliteralcaneasilygettiring.It’struethatJavaScriptdevelopersareusedtoendtheirvariablesandfunctiondefinitionswithsemicolons(;),andtryingtowriteabigModuleusingcommas(,)aftereachpropertycaneasilyleadtosyntacticerrors.

Page 129: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

EventhoughthispatternmakesiteasytodeclarenestedNamespacesforaModule,itcanalsoleadtobigcodestructureswithbadreadabilityincaseweneedseverallevelsofnesting.Forexample,let’stakealookatthefollowingskeletonofaTodoapplication:

varmyTodoApp={

todos:[],

addTodo:function(todo){this.todos.push(todo);},

getTodos:function(){returnthis.todos;},

updateTodo:function(todo){/*...*/},

imports:{

fromGDrive:function(){/*...*/},

fromUrl:function(){/*...*/},

fromText:function(){/*...*/}

},

exports:{

gDrivePublicKey:'#wnanqAASnsmkkw',

toGDrive:function(){/*...*/},

toFile:function(){/*...*/},

},

share:{

toTwitter:function(todo){/*...*/}

}

};

Fortunately,thiscanbeeasilyfixedbysplittingtheobjectliteraltomultipleassignmentsforeachsubmodule(andpreferablytodifferentfiles)asfollows:

varmyTodoApp={

todos:[],

addTodo:function(todo){this.todos.push(todo);},

getTodos:function(){returnthis.todos;},

updateTodo:function(todo){/*...*/},

};

/*…*/

myTodoApp.exports={

gDrivePublicKey:'#wnanqAASnsmkkw',

toGDrive:function(){/*...*/},

toFile:function(){/*...*/},

};

/*...*/

Page 130: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 131: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

TheModulePatternThekeyconceptofthebasicModulePatternistoprovideasimplefunction,class,orobjectthattherestoftheapplicationcanuse,throughawell-knownvariablename.ItenablesustoprovideaminimalAPIforaModule,byhidingthepartsoftheimplementationthatdonotneedtobeexposed.Thisway,wealsoavoidpollutingtheGlobalNamespacewithvariablesandutilityfunctionsthatareneededforinternalusebyourModule.

Page 132: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

TheIIFEbuildingblockInthissubsection,wewillgetasmallintroductiontotheIIFEDesignPatternsinceit’sanintegralpartforallthevariantsoftheModulePatternthatwewillseeinthischapter.TheImmediatelyInvokedFunctionExpression(IIFE)isaverycommonlyusedDesignPatternamongJavaScriptdevelopersbecauseofthecleanwayinwhichitisolatesblocksofcode.IntheModulePattern,anIIFEisusedtowrapalltheimplementationinordertoavoidpollutingtheGlobalNamespaceandprovideprivacytothedeclarationstotheModuleitself.

EachIIFEcreatesaClosurewiththevariablesandfunctionsdeclaredinsideit.TheClosurethatiscreatedenablestheexposedfunctionoftheIIFEtokeepreferencestotherestofthedeclarationsoftheirenvironmentandaccessthemnormallywhenexecutedfromotherpartsofanimplementation.Asaresult,thenon-exposeddeclarationsoftheIIFEdonotleakoutsideit,butarekeptprivateandareaccessibleonlybythefunctionsthatarepartofthecreatedClosure.

NoteFormoreinformationonIIFEsandClosures,youcanvisithttps://developer.mozilla.org/en-US/docs/Glossary/IIFEandhttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures.

AnIIFEismostcommonlyusedasfollows:

(function(){

varx=7;

console.log(x);

//prints7

})();

Sincetheprecedingcodeconstructmightlookbizarreonfirstsight,let’sseethepiecesthatitiscomposedfrom.AnIIFEisalmostequivalenttodeclaringananonymousfunction,assigningittoavariable,andthenexecutingit,asshowninthefollowingcode:

vartmp=function(){

varx=7;

console.log(x);

};

tmp();

//or

(tmp)();

Intheprecedingcode,wedefineafunctionexpressionandexecuteitusingtmp().Since,inJavaScript,wecanuseparenthesesaroundanidentifierwithoutchangingitsmeaning,wecanalsoexecutethestoredfunctionwith(tmp)();.Thefinalstep,inordertoturntheprecedingcodeintoanIIFE,istoreplacethetmpvariablewiththeactualanonymousfunctiondeclaration.

Aswesawearlier,theonlydifferenceisthat,withanIIFE,wedoneedtodeclarea

Page 133: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

variablejusttoholdthefunctionitself.Weonlycreateananonymousfunctionandinvokeitimmediatelyrightafterdefiningit.

SincethecreationofanIIFEcanbeachievedinseveralways,whichmightlooklikeanexerciseofJavaScript’srules,thecommunityofJavaScriptdevelopershasconcludedtotheabovecodestructureasapointofreferenceforthispattern.ThiswayofcreatinganIIFEisconsideredtohavebetterreadabilityandisusedbylargelibrariesandasaresultofitsadoption,developerscaneasilyrecognizeitinsidelargeJavaScriptimplementations.

Anexampleoftheless-widely-usedwaystocreateanIIFEisthefollowingcodestructure:

(function(){

//code

}());

Page 134: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

ThesimpleIIFEModulePatternSincethereisnoactualnameforthispattern,itisrecognizedbythefactthatthedefinedModulereturnsasingleentity.Forreferenceonhowtocreateareusablelibraryusingthispattern,wewillrewritethesimpleguidModulethatwesawearlier.Theresultingimplementationwilllookasfollows:

varsimpleguid=(function(){

varsimpleguid={};

varguid;

simpleguid.init=function(){

guid=1;

};

simpleguid.increaseCounter=function(){

guid++;

};

simpleguid.getNext=function(){

varnextGuid=guid;

this.increaseCounter();

returnnextGuid;

};

simpleguid.init();

returnsimpleguid;

})();

ThispatternusesanIIFEtodefineanobjectthatactsastheModulecontainer,attachespropertiestoit,andlaterreturnsit.ThevariablesimpleguidinthefirstlineoftheprecedingcodeisusedastheNamespaceoftheModuleandisassignedwiththevaluethatisreturnedbytheIIFE.ThemethodsandpropertiesthataredefinedonthereturnedobjectaretheonlyexposedpartsoftheModulesandconstituteitspublicAPI.

Onceagain,thispatternallowsustousethethiskeyword,inordertoaccesstheexposedmethodsandpropertiesofourModule.Furthermore,italsoprovidestheflexibilitytoexecuteanyrequiredinitializationcodebeforecompletingtheModule’sdefinition.

UnliketheObjectLiteralPattern,theModulePatternenablesustocreateactualprivatemembersinourModules.VariablesdeclaredinsidetheIIFE,thatarenotattachedtothereturnvalue,suchastheguidvariable,actasprivatemembersandareonlyaccessibleinsidetheModulebyrestmembersofthecreatedClosure.

Lastly,incaseweneedtodefineanestedNamespace,allwehavetodoischangetheassignmentofthevaluereturnedbytheIIFE.Asanexampleofanapplicationstructuredwithsubmodules,let’sseehowwewilldefinetheexportingsubmodulefortheTodoapplicationskeletonthatwesawearlier:

varmyTodoApp=(function(){

varmyTodoApp={};

Page 135: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

vartodos=[];

myTodoApp.addTodo=function(todo){

todos.push(todo);

};

myTodoApp.getTodos=function(){

returntodos;

};

returnmyTodoApp;

})();

myTodoApp.exports=(function(){

varexports={};

vargDrivePublicKey='#wnanqAASnsmkkw';

exports.toGDrive=function(){/*...*/};

exports.toFile=function(){/*...*/};

returnexports;

})();

Giventhatourapplication’sNamespacemyTodoApphasalreadybeendefinedearlier,theexportssubmodulecanbedefinedasasimplepropertyonit.AgoodpracticetofollowwillbetocreateonefileforeachoneoftheaboveModules,usingtheIIFEsasthelandmarkstosplityourcode.Awidelyusednamingconvention,whichisalsosuggestedbyGoogle’sJavaScriptStyleGuide,istouselowercasenamingforyourfilesandadddashestoseparatesubmodules.Forexample,byfollowingthisnamingconvention,theprecedingcodeshouldbedefinedintwofilesnamedasmytodoapp.jsandmytodoapp-exports.jsforeachModule,respectively.

HowitisusedbyjQueryTheModulePatternisusedwithinjQueryitself,inordertoisolatethesourcecodeoftheCSSselectorengine(Sizzle),whichpowersthe$()function,fromtherestofthejQuerysource.Fromthebeginning,SizzlewasabigpartofthejQuerysource,whichiscurrentlycountingabout2135linesofcode;since2009,ithasbeensplitintoaseparateprojectnamedSizzle,soitcanbemoreeasilymaintained,bedevelopedindependently,andbereusablebyotherlibraries:

varSizzle=(function(window){

/*179linesofcode*/

functionSizzle(selector,context,results,seed){

/*131linesofcode*/

}

/*

Page 136: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

1804linesofcode,definingmethodslike:

Sizzle.attr

Sizzle.compile

Sizzle.contains

Sizzle.getText

Sizzle.matches

Sizzle.matchesSelector

Sizzle.select

*/

returnSizzle;

})(window);

jQuery.find=Sizzle;

SizzleisaddedtothejQuery’ssourceinsideanIIFE,whileitsmainfunctionisreturnedandassignedtojQuery.findforuse.

NoteFormoreinformationonSizzle,youcanvisithttps://github.com/jquery/sizzle.

Page 137: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

TheNamespaceParameterModulevariantInthisvariant,insteadofreturninganobjectfromourIIFEandthenassigningittothevariablethatactsastheNamespaceoftheModule,wecreatetheNamespaceandpassitasaparametertotheIIFEitself:

(function(simpleguid){

varguid;

simpleguid.init=function(){

guid=1;

};

simpleguid.increaseCounter=function(){

guid++;

};

simpleguid.getNext=function(){

varnextGuid=guid;

this.increaseCounter();

returnnextGuid;

};

simpleguid.init();

})(window.simpleguid=window.simpleguid||{});

ThelastlineoftheModuledefinitiontestswhethertheModuleisalreadydefined;incaseitisnot,itinitializesittoanemptyobjectliteralandassignsittotheglobalobject(window).Inanycase,thesimpleguidparameterinthefirstlineoftheIIFEwillholdtheModule’sNamespace.

NoteTheaboveexpressionisalmostequivalenttowriting:

window.simpleguid=window.simpleguid!==undefined?window.simpleguid:

{};

UsingthelogicalORoperator(||)makestheexpressionbothshorterandmorereadable.Moreover,thisisapatternthatmostwebdevelopershavelearnedtoeasilyrecognize,anditappearsinalotofdevelopmentpatternsandbestpractices.

Onceagain,thispatternallowsustousethethiskeywordtoaccesspublicmembersfromwithintheexportedmethodsoftheModule.Atthesametime,itallowsustokeepsomefunctionsandvariablesprivate,whichwillbeaccessibleonlybyotherfunctionsoftheModule.

Eventhoughit’sconsideredagoodpracticetodefineeachModuletoitsownJSfile,thisvariantalsoallowsustosplittheimplementationoflargeModulestomorethanonefile.ThisbenefitcomesasaresultofcheckingwhethertheModuleisalreadydefined,beforeinitializingittoanemptyobject.Thismightbeusefulinsomecases,withtheonlylimitationbeingthateachpartialfileofaModulecanaccesstheprivatemembersdefinedinitsownIIFE.

Page 138: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

Moreover,inordertoavoidrepetition,wecanuseasimpleridentifierfortheparameteroftheIIFEandwriteourModuleasfollows:

(function(namespace){

/*…*/

namespace.getNext=function(){

varnextGuid=guid;

this.increaseCounter();

returnnextGuid;

};

namespace.init();

})(window.simpleguid=window.simpleguid||{});

WhenitcomestoapplicationswithnestedNamespaces,thispatternmightstartfeelingalittleuncomfortabletoread.ThelastlineoftheModuledefinitionwillstarttogetlongerforeveryextralevelofnestednamespacingthatwedefine.Forexample,let’sseehowtheexportssubmoduleofourTodoapplicationwouldlook:

(function(exports){

vargDrivePublicKey='#wnanqAASnsmkkw';

exports.toGDrive=function(){/*...*/};

exports.toFile=function(){/*...*/};

})(myTodoApp.exports=myTodoApp.exports||{});

Asyoucansee,eachextralevelofthenestedNamespaceneedstobeaddedonbothsidesoftheassignmentthatispassedasaparametertotheIIFE.ForapplicationswithcomplexfeaturesthatleadtomultiplelevelsofnestedNamespaces,thiscouldleadtoModuledefinitionslookingsomethinglikethis:

(function(smallModule){

smallModule.method=function(){/*...*/};

returnsmallModule;

})(myApp.bigFeature.featurePart.smallModule=

myApp.bigFeature.featurePart.smallModule||{});

Moreover,ifwewanttoprovidethesamesafetyguaranties,asintheoriginalcodesample,thenwewouldneedtoaddsimilarsafechecksforeachNamespacelevel.Withthisinmind,theexportsModuleofourTodoapplicationthatwesawearlierwouldneedtohavethefollowingform:

(function(exports){

vargDrivePublicKey='#wnanqAASnsmkkw';

exports.toGDrive=function(){/*...*/};

exports.toFile=function(){/*...*/};

Page 139: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

})((window.myTodoApp=window.myTodoApp||{},myTodoApp.exports=

myTodoApp.exports||{}));

Asseenintheprecedingcode,weusedthecommaoperator(,)toseparateeachnamespaceexistencecheckandwrappedthewholeexpressioninanextrapairofparenthesissothatthewholeexpressionisusedasthefirstparameteroftheIIFE.Usingthecommaoperator(,)tojoinexpressionswillleadthemtobeevaluatedinorderandpasstheresultofthelastevaluatedexpressionastheparameteroftheIIFE,andthatresultwillbeusedastheNamespaceoftheModule.Keepinmindthat,foreachextranestedNamespacelevel,weneedtoaddanextraexistencecheckexpressionusingthecommaoperator(,).

Adisadvantageofthispattern,especiallywhenusedfornestednamespacing,isthattheNamespacedefinitionoftheModuleisattheendofthefile.EventhoughitishighlyrecommendedtonameyourJSfilessothattheyproperlyrepresenttheModulesthattheycontain,forexample,mytodoapp.exports.js;nothavingtheNamespacenearthetopofthefilecansometimesbecounterproductiveormisleading.Aneasywork-aroundforthisproblemwouldbetodefinetheNamespacebeforetheIIFEandthenpassitasaparameter.Forexample,theprecedingcodeusingthistechniquewouldbetransformedtosomethingasfollows:

window.myTodoApp=window.myTodoApp||{};

myTodoApp.exports=myTodoApp.exports||{};

(function(exports){

vargDrivePublicKey='#wnanqAASnsmkkw';

exports.toGDrive=function(){/*...*/};

exports.toFile=function(){/*...*/};

})(myTodoApp.exports);

Page 140: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

TheIIFE-containedModulevariantLikeinthepreviousvariantsoftheModulePattern,thisvariantdoesnotactuallyhaveaspecificvariantname,butisrecognizedbythewaythecodeisstructured.ThekeyconceptofthisvariantistomovealltheModule’scodeinsidetheIIFE:

(function(){

window.simpleguid=window.simpleguid||{};

varguid;

simpleguid.init=function(){

guid=1;

};

simpleguid.increaseCounter=function(){

guid++;

};

simpleguid.getNext=function(){

varnextGuid=guid;

this.increaseCounter();

returnnextGuid;

};

simpleguid.init();

})();

ThisvariantlooksverysimilartothepreviousoneandmainlydiffersinthewaythattheNamespaceiscreated.Firstofall,itkeepstheNamespacecheckandinitializationnearthetopoftheModule,likeaheading,makingourcodemorereadableregardlessofwhetherweuseaseparatefilefortheModuleornot.LikeothervariantsoftheModulePattern,itsupportsprivatemembersforourModulesandalsoallowsustousethethiskeywordtoaccesspublicmethodsandproperties,makingourcodelookmoreobject-oriented.

RegardingimplementationswithnestedNamespaces,thecodestructureoftheexportssubmoduleofourTodoapplicationskeletonwilllookasfollows:

(function(){

window.myTodoApp=window.myTodoApp||{};

myTodoApp.exports=myTodoApp.exports||{};

vargDrivePublicKey='#wnanqAASnsmkkw';

myTodoApp.exports.toGDrive=function(){/*...*/};

myTodoApp.exports.toFile=function(){/*...*/};

})();

Asseenintheprecedingcode,wealsoborrowedtheNamespacedefinitionchecksfromthepreviousvariantand,likewise,appliedittoeverylevelofnestednamespacing.Even

Page 141: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

thoughthisisnotabsolutelynecessary,itbringsthebenefitsthatwediscussedearliersuchasenablingustosplitaModuledefinitionintoseveralfilesandevenresultsinamoreerror-tolerantimplementationregardingtheimportorderoftheapplication’sModules.

Page 142: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 143: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

TheRevealingModulePatternTheRevealingModulePatternisavariantoftheModulePatternwithaknownandwidelyrecognizedname.WhatmakesthispatternspecialisthatitcombinesthebestpartsoftheObjectLiteralPatternandtheModulePattern.AllthemembersoftheModulearedeclaredinsideanIIFE,whichattheend,returnsanObjectLiteralcontainingonlythepublicmembersoftheModuleandisassignedtothevariablethatactsasourNamespace:

varsimpleguid=(function(){

varguid=1;

functioninit(){

guid=1;

}

functionincreaseCounter(){

guid++;

}

functiongetNext(){

varnextGuid=guid;

increaseCounter();

returnnextGuid;

}

return{

init:init,

getNext:getNext

};

})();

OneofthemainbenefitsofthispatternthatdifferentiatesitfromothervariantsisthatitallowsustowriteallthecodeofourModuleinsidetheIIFE,justlikewewouldiftheywouldbedeclaredontheGlobalNamespace.Moreover,thispatterndoesnotrequireanyvariationonthewaythatthepublicandprivatemembersaredeclared,makingthecodeoftheModulelookuniform.

SincethereturnedObjectLiteraldefinesthepubliclyavailablemembersoftheModule,itisalsoaconvenienteasywaytoinspectitspublicAPI,evenifitiswrittenbysomeoneelse.Moreover,incaseweneedtoexposeaprivatemethodonourModule’sAPI,allweneedtodoisaddanextrapropertytothereturnedObjectLiteralwithoutchanginganypartofitsdefinition.Additionally,theuseofanObjectLiteralenablesustochangetheexposedidentifiersfortheModule’sAPI,withoutchangingthenamesusedbytheModule’simplementationinternally.

Evenifthisisnotclearlyvisible,thethiskeywordcanbeusedforcallsbetweenthepublicmembersoftheModule.Unfortunately,usingthethiskeywordisdiscouragedforthispattern,sinceitbreakstheuniformityofthefunctiondeclarationsandcaneasilyleadtoerrors,especiallywhenchangingthevisibilityofapublicmethodtoprivate.

Page 144: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

SincetheNamespacedefinitioniskeptoutsidethebodyoftheIIFE,thispatternclearlyseparatestheNamespacedefinitionfromtheactualimplementationoftheModule.UsingthispatterntodefineaModuleinanestedNamespacedoesnotaffecttheModule’simplementation,whichwillnotlookdifferentatanypointfromatop-levelNamespaceModule.RewritingtheexportssubmoduleofourTodoskeletonapplicationusingthispatternwillmakeitlooklikethis:

myTodoApp.exports=(function(){

vargDrivePublicKey='#wnanqAASnsmkkw';

functiontoGDrive(){/*...*/}

functiontoFile(){/*...*/}

return{

toGDrive:toGDrive,

toFile:toFile

};

})();

Asaresultofthisseparation,wehavelesscoderepetitionandwecaneasilychangetheNamespaceofaModulewithoutaffectingitsimplementationatall.

Page 145: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 146: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

UsingES5StrictModeAsmallbutpreciousadditiontoalltheModulePatternsthatuseIIFEsastheirbasicbuildingblocks,istheuseofStrictModeforJavaScriptexecution.ThiswasstandardizedinthefiftheditionofJavaScript,andisanopt-inexecutionmodewithslightlydifferentsemantics,inordertopreventsomeofthecommonpitfallsofJavaScript,butalsohavingbackwardscompatibilityinmind.

Underthismode,theJavaScriptruntimeenginewillpreventyoufromaccidentallycreatingaglobalvariableandpollutingtheGlobalNamespace.Eveninnot-so-largeapplications,itisquitepossiblethatavardeclarationbeforetheinitialassignmentofavariablecanbemissing,automaticallypromotingthattoaglobalvariable.Topreventthiscase,strictmodethrowsanerrorincaseanassignmentisissuedtoanundeclaredvariable.ThefollowingimageshowtheerrorthatisthrownbyFirefoxandChromewhenaStrictModeviolationhappens.

Thismodecanbeenabledbyaddingthe"usestrict";or'usestrict';statementbeforeanyotherstatements.Eventhoughthiscanbeenabledontheglobalscope,itishighlyrecommendedthatyouenableitonlyinsidethescopeofafunction.Enablingitontheglobalscopemightmakethird-partylibrariesthatarenon-strict-modecompliantstopworkingormisbehave.Ontheotherhand,thebestplacetoenableStrictModeisinsidetheIIFEofaModule.TheStrictModewillberecursivelyappliedtoallnestedNamespaces,methods,andfunctionsofthatIIFE.

NoteFormoreinformationonJavaScript’sstrictexecutionmode,youcanvisithttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode.

Page 147: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 148: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

IntroducingES6ModulesEventhoughJavaScriptinitiallyhadnobuilt-inpackagingandnamespacingsupportlikeotherprogramminglanguages,webdevelopersfilledthegapsbydefiningandadoptingsomedesignpatternsforthispurpose.ThesesoftwaredevelopmentpracticesworkedaroundthemissingfeaturesofJavaScriptandallowedlargeandscalableimplementationsofcomplexapplicationsonaprogramminglanguagethatsomeyearsagowasmostlyusedforformvalidation.

Thiswasuntilthe6thversionofJavaScript,commonlyreferredtoasES6,wasreleasedasastandardonJune2015andintroducedtheconceptofModulesaspartofthelanguage.

NoteES6isanabbreviationofECMAScript6thedition,whichisalsoreferredtoasHarmonyorECMAScript2015,whereECMAScriptisthetermthatisusedforthestandardizationprocessofJavaScript.Thespecificationcanbefoundathttp://www.ecma-international.org/ecma-262/6.0/index.html#sec-modules.

AsanexampleofES6Modules,wewillseeoneofthemanywaysinwhichthesimpleguidModulecanbewritten:

vares6simpleguid={};

exportdefaultes6simpleguid;

varguid;

es6simpleguid.init=function(){

guid=1;

};

es6simpleguid.increaseCounter=function(){

guid++;

};

es6simpleguid.getNext=function(){

varnextGuid=guid;

this.increaseCounter();

returnnextGuid;

};

es6simpleguid.init();

Ifwesavethisasafilenamedes6simpleguid.js,thenwecanimportanduseitinadifferentfilebysimplywritingthefollowingcode:

importes6simpleguidfrom'es6simpleguid';

console.log(es6simpleguid.getNext());

SinceES6ModulesarebydefaultinStrictMode,writingyourModulestodayusingyourpreferredModulePatternvariantwithStrictModeenabledwillmakeyourtransitiontoES6Moduleseasier.Someoftheabovepatternsrequireveryfewchangestoachievethis.

Page 149: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

Forexample,intheIIFE-containedModulePatternvariant,allthatisneededisremovetheIIFEandthe"usestrict";statement,replacethecreationoftheModule’sNamespacewithavariable,andusetheexportkeywordonit.

Unfortunately,atthetimeofwritingthisbook,nobrowserhas100%supportforES6Modules.Asaresult,specialloadersortoolsthattranspileES6toES5arerequiredsothatwecanstartwritingourcodeusingthenewfeaturesofES6.

NoteFormoreinformation,youcanvisitES6Moduleloader’sdocumentationpageathttps://github.com/ModuleLoader/es6-module-loader,andBabeltranspiler(earlierknownasES6toES5)athttp://babeljs.io/.

Page 150: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 151: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

UsingModulesinjQueryapplicationsInordertodemonstratehowtheModulePatterncanleadtoabetterapplicationstructure,wewillreimplementthedashboardexamplethatwesawinthepreviouschapters.Wewillincludeallthefunctionalitiesthatwehaveseenuntilnow,includingthecounteroftheopeninformationboxes.TheHTMLandCSScodeusedisexactlythesameasinthepreviouschapterand,asaresult,ourdashboardlooksexactlythesameasbefore:

Forthisdemonstration,wewillrefactorourJavaScriptcodeintofoursmallModulesusingthesimpleIIFE-containedModulevariant.ThedashboardModulewillactasthemainentryofcodeexecutionandalsoasthecentralcoordinationpointofthedashboardapplication.Thecategoriessubmodulewillberesponsiblefortheimplementationoftheupper-toppartofourdashboard.Thisincludescategoryselection,thepresentationofappropriatebuttons,andthehandlingofbuttonclicks.TheinformationBoxsubmodulewillberesponsibleforthemainpartofourdashboard.Itwillprovidemethodstocreateandremoveinformationboxesfromthedashboard.Finally,thecountersubmodulewillberesponsibleforkeepingthefieldwiththenumberofthecurrentlyopeninformationboxesup-to-date,respondingtotheuseractions.

AsinglechangethatweneedtomaketotheHTMLofthepageinordertosupportthismultimodulearchitectureislimitedtothewayinwhichtheJavaScriptfilesareincluded:

<scripttype="text/javascript"src="jquery.js"></script>

<scripttype="text/javascript"src="dashboard.js"></script>

<scripttype="text/javascript"src="dashboard.categories.js"></script>

<scripttype="text/javascript"src="dashboard.informationbox.js">

</script>

<scripttype="text/javascript"src="dashboard.counter.js"></script>

TipEvenifthismultifilestructuremakesthedevelopmentanddebuggingprocessesaloteasier,itisrecommendedthatwecombineallthesefilesbeforemovingourapplicationtoaproductionenvironment.Severaltoolsspecializedforthisjobexist;forexample,theverysimpleandeffectivegrunt-contrib-concatprojectthatisavailableathttps://github.com/gruntjs/grunt-contrib-concat.

Page 152: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

ThemaindashboardmoduleTheresultingcodeforthedashboardmodulewilllookasfollows:

(function(){

'usestrict';

window.dashboard=window.dashboard||{};

dashboard.$container=null;

dashboard.init=function(){

dashboard.$container=$('.dashboardContainer');

dashboard.categories.init();

dashboard.informationBox.init();

dashboard.counter.init();

};

$(document).ready(dashboard.init);

})();

Aswealreadymentioned,thedashboardmodulewillbethecentralpointofourapplication.Sincethisisthestartingpointofexecutionforourapplication,itsmaindutyistodoalltherequiredinitializationsforitselfandeachsubmodule.Theinvocationoftheinit()methodiswrappedinsideacalltothe$(document).ready()methodsothatitsexecutionisdelayeduntiltheDOMtreeofthepageisfullyloaded.

Oneimportantthingtonoteisthat,duringtheinitialization,wedoaDOMtraversalinordertofindthecontainerelementofthedashboardandstoreittoapublicpropertyoftheModulenamed$container.ThiselementwillbeusedbyallthemethodsofthedashboardthatneedtoaccesstheDOMtree,inordertoscopetheircodeinsidethatcontainerelement,removingtheneedtoconstantlytraversethewholeDOMtreeusingcomplexselectors.KeepingreferencestokeyDOMelementsandreusingtheminthedifferentsubmodules,canmaketheapplicationsnappierandalsolessenthechanceofaccidentallyinterferingwiththerestofthepage;thus,leadingtolessbugsthatarealsoeasiertoresolve.

TipCacheelementsbutavoidmemoryleaks.

KeepinmindthatmaintainingreferencestoDOMelementsthatareconstantlyaddedandremovedfromthepageaddsextracomplexitytoourapplication.Thiscanevenleadtomemoryleaksincaseweareaccidentallykeepingareferencetoanelementthathasalreadybeenremovedfromthepage.Forsuchelements,suchastheinformationboxes,itmightbesaferandmoreeffectivetohavedelegatedhandlingfortheeventstriggeredonthemandtodoascopedDOMtraversalwhenneeded,inordertoretrieveajQueryobjectwithfreshreferencesoftheelements.

Page 153: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

ThecategoriesmoduleLet’sproceedwiththecategoriessubmodule:

(function(){

'usestrict';

dashboard.categories=dashboard.categories||{};

dashboard.categories.init=function(){

dashboard.$container.find('#categoriesSelector').change(function()

{

var$selector=$(this);

varcategoryIndex=+$selector.val();

dashboard.categories.selectCategory(categoryIndex);

});

dashboard.$container.find('.dashboardCategories').on('click',

'button',function(){

var$button=$(this);

varitemName=$button.text();

dashboard.informationBox.openNew(itemName);

});

};

dashboard.categories.selectCategory=function(categoryIndex){

var$dashboardCategories=

dashboard.$container.find('.dashboardCategory');

var$selectedItem=$dashboardCategories.eq(categoryIndex).show();

$dashboardCategories.not($selectedItem).hide();

};

})();

Thissubmodule’sinitializationmethodusesthereferencetothe$containerelementthatthemainModuleprovidesandaddstwoobserverstothepage.Thefirsthandlesthechangeeventonthe<select>categoryandcallstheselectCategory()methodwiththenumericvalueoftheselectedcategory.TheselectCategory()methodofthissubmodulewillthenhandlerevealingtheappropriatecategoryitems,decouplingitfromtheeventhandlingcodeandmakingitareusablefunctionalityavailabletotheentireapplication.

Rightafterthis,wecreateasingleDelegatedEventObserverthathandlestheclickeventonthe<button>categoryitem.Itextractsthetextofthe<button>pressedandcallstheopenNew()methodoftheinformationBoxsubmodulethatcontainsalltheimplementationrelatedtoinformationboxes.Inanon-demogradeapplication,aparametertosuchamethodwouldprobablybeanidentifierinsteadofatextvaluethatwouldbeusedtoretrievemoredetailsfromaremoteserver.

Page 154: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

TheinformationBoxmoduleTheinformationBoxsubmodulethatcontainstheimplementationpartsrelatedtothemainareaofourdashboardhasthefollowingform:

(function(){

'usestrict';

dashboard.informationBox=dashboard.informationBox||{};

var$boxContainer=null;

dashboard.informationBox.init=function(){

$boxContainer=dashboard.$container.find('.boxContainer');

$boxContainer.on('click','.boxCloseButton',function(){

var$button=$(this);

dashboard.informationBox.close($button);

});

};

dashboard.informationBox.openNew=function(itemName){

varboxHtml='<divclass="boxsizer"><articleclass="box">'+

'<headerclass="boxHeader">'+

itemName+

'<buttonclass="boxCloseButton">&#10006;'+

'</button>'+

'</header>'+

'Informationboxregarding'+itemName+

'</article></div>';

$boxContainer.append(boxHtml);

};

dashboard.informationBox.close=function($boxElement){

$boxElement.closest('.boxsizer').remove();

};

})();

Thefirstthingthatthissubmodule’sinitializationcodedoesisretrieveandstoreareferenceofthecontainerthatholdstheinformationboxestothe$boxContainervariable,usingthe$containerpropertyofthedashboardforscoping.

TheopenNew()methodisresponsibleforcreatingtheHTMLrequiredforanewinformationboxandaddingittothedashboardusingthe$boxContainervariable,whichactslikeaprivatememberoftheModule,andisusedforcachingthereferenceofthepreviouslyassignedDOMelement.Thisisagoodpracticethatcanimprovetheapplication’sperformance,sincethestoredelementisneverremovedfromthepageandisusedduringtheinitializationandtheopenNew()methodsoftheModule.Thisway,wenolongerneedtoexecuteslowDOMtraversalseverytimetheopenNew()methodiscalled.

Theclose()method,ontheotherhand,isresponsibleforremovinganexistinginformationboxfromthedashboard.ItreceivesajQuerycompositecollectionobjectasa

Page 155: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

parameterrelatedtothetargetinformationbox,whichisbasedonthewaythatthe$.fn.closest()methodworks,andcaneitherbetheboxelementcontaineroranyofitsdescendants.

TipImplementationsofmethodsthatprovideflexibilityregardingthewaythattheycanbecalledcanmakethemusablebymorepartsofalargeapplication.Thenextlogicalstepforthismethod,whichisleftasanexercisetothereader,wouldbetomakeitacceptasaparameter,theindex,oranidentifieroftheinformationboxthatneedstobeclosed.

Page 156: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

ThecountermoduleLastly,hereishowwerewrotethecounterimplementation,whichwesawinthepreviouschapter,asanindependentsubmodule:

(function(){

'usestrict';

dashboard.counter=dashboard.counter||{};

vardashboardItemCounter;

var$counter;

dashboard.counter.init=function(){

$counter=$('#dashboardItemCounter');

var$boxContainer=dashboard.$container.find('.boxContainer');

varinitialCount=$boxContainer.find('.boxsizer').length;

dashboard.counter.setValue(initialCount);

dashboard.$container.find('.dashboardCategories').on('click',

'button',function(){

dashboard.counter.setValue(dashboardItemCounter+1);

});

$boxContainer.on('click','.boxCloseButton',function(){

dashboard.counter.setValue(dashboardItemCounter-1);

});

};

dashboard.counter.setValue=function(value){

dashboardItemCounter=value;

$counter.text(dashboardItemCounter);

};

})();

Forthissubmodule,weareusingthe$countervariableasaprivatemembertocacheareferencetotheelementthatdisplaysthecount.AnotherprivatememberoftheModuleisthedashboardItemCountervariable,whichatanypointoftimewillholdthenumberofvisibleinformationboxesinthedashboard.KeepingsuchinformationonthemembersofourModulesreducesthetimesweneedtoreachtheDOMtreetoextractinformationonthestateoftheapplication,makingtheimplementationmoreefficient.

TipPreservingthestateoftheapplicationinthepropertiesofJavaScriptobjectsorModulesinsteadofreachingtheDOMtoextractthem,isaverygoodpracticethatmakestheapplication’sarchitecturemoreobject-oriented,andisalsoadoptedbymostofthemodernwebdevelopmentframeworks.

DuringtheinitializationoftheModule,wearegivinganinitialvaluetoourcountervariablesothatwearenolongerdependentontheinitialHTMLofthepageandhavea

Page 157: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

morerobustimplementation.Moreover,weareattachingtwoDelegatedEventObservers,oneforclicksthatwillleadtothecreationofnewinformationboxesandanotheroneforclicksthatwillclosethem.

Page 158: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

OverviewoftheimplementationWiththeabove,wecompletedtherewriteofthedashboardskeletonapplicationtoamodulararchitecture.Alltheavailableactionsareexposedaspublicmethodsofeachofoursubmodulesthatcanbeinvokedprogrammaticallyandthiswaytheyaredecoupledfromtheeventsthattriggerthem.

Agoodexerciseforthereaderwouldbetopromotethedecouplingevenfurther,byalsoadoptingthePublisher/SubscriberPatternintheaboveimplementation.ThefactthatthecodeisalreadystructuredintoModuleswillmakesuchchangealoteasiertoimplement.

Anotherpartthatcanbeimplementedinadifferentwayisthewayinwhichthesubmodulesareinitialized.InsteadofexplicitlyorchestratingtheinitializationofeachModuleinourmaindashboardModule,wecouldinsteadinitializeeachsubmoduleonitsownbywrappingtheinvocationoftheinit()methodina$(document).ready()callandissuingitsinitializationrightafteritsdeclaration.Ontheotherhand,nothavingacentralpointtocoordinatetheinitializationsandrelyingonpageeventscanfeellessdeterministic.AnotherwaytoimplementitwouldbelikethePublisher/SubscriberPattern,byexposingaregisterForInit()methodonourmainModule,whichwouldkeeptrackoftheModulesthathavebeenrequestedtobeinitializedusinganarray.

NoteFormorejQuerycodeorganizationtips,youcanvisithttp://learn.jquery.com/code-organization/concepts/.

Page 159: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 160: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

SummaryInthischapter,welearnedtheconceptsofModulesandNamespacesandalsothebenefitsthatcomefromtheiradoptioninlargeapplications.Wehadanin-depthanalysisofthemostwidelyadoptedpatternsandcomparedtheirbenefitsandlimitations.WelearnedbyexamplehowtodevelopModulesusingtheObjectLiteralPattern,thevariantsoftheModulePattern,andtheRevealingModulePattern.

WecontinuedwithasmallintroductiontoES5’sStrictModeandsawhowitcanbenefittoday’sModules.ThenweproceededbylearningsomedetailsaboutthestandardizedbutnotyetwidelysupportedES6Modules.Lastly,wesawhowthearchitectureofthedashboardapplicationcanchangedramaticallyafterusingtheModulePatterninitsimplementation.

NowthatwehavecompletedourintroductiononhowtouseModulesandNamespaces,wecanmoveontothenextchapterwherewewillbeintroducedtothefacadepattern.Inthenextchapter,wewilllearnaboutthephilosophyoffacadesandtheuniformwaythattheydefinehowcodeabstractionsshouldbecreatedsothattheyareeasilyunderstandableandreusablebyotherdevelopers.

Page 161: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 162: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

Chapter5.TheFacadePatternInthischapter,wewillshowcasetheFacadePattern,astructuraldesignpatternthattriestodefineauniformwayregardinghowdevelopersshouldcreateabstractionsintheircode.Initially,wewillusethispatterntowrapcomplexAPIsandexposesimpleronesthatfocusontheneedsofourapplication.WewillseehowjQueryembracestheconceptsofthispatterninitsimplementation,howitachievesencapsulatingcompleximplementationsthatareintegralpartsofthewebdeveloper’stool-beltintoeasy-to-useAPI’s,andhowthisplaysacriticalroleforitswideadoption.

Inthischapter,wewill:

IntroducetheFacadePatternDocumentitskeyconceptsandbenefitsSeehowjQueryusesitinitsimplementationWriteanexampleimplementationwhereFacadesareusedtocompletelyabstractanddecoupleathird-partylibrary

Page 163: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

IntroducingtheFacadePatternTheFacadeisastructuralsoftwaredesignpatternthatdealswithhowabstractionsofthevariouspartsofanimplementationshouldbecreated.ThekeyconceptoftheFacadePatternistoabstractanexistingimplementationandprovideasimplifiedAPIthatbettermatchestheusecasesofthedevelopedapplication.AccordingtomostComputerSciencebibliographiesdescribingthispattern,aFacadeismostcommonlyimplementedasaspecializedclassthatisusedtosegmenttheimplementationofanapplicationintosmallerpiecesofcode,whileprovidinganinterfacethatcompletelyhidestheencapsulatedcomplexity.Inthewebdevelopmentworld,itisalsocommontouseplainobjectsorfunctionsfortheimplementationofaFacade,takingadvantageofthewayinwhichJavaScripttreatsfunctionsasobjects.

Inapplicationsthathaveamodularstructure,liketheexamplesofthepreviouschapter,itisalsocommontoimplementFacadesasseparatemoduleswiththeirownnamespace.Moreover,foralargerimplementationwithverycomplexparts,anapproachwithmultiplelevelsofFacadescanalsobefollowed.Onceagain,theFacadeswillbeimplementedasmodulesandsubmodules,havingthetop-levelFacadeorchestratingthemethodsofitssubmodules,whileprovidinganAPIthatcompletelyhidesthecomplexityoftheentiresubsystem.

Page 164: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 165: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

ThebenefitsofthispatternMostofthetime,theFacadePatternisadoptedforimplementationpartsthathavearelativelyhighdegreeofcomplexityandareusedinseveralplacesofanapplication,whereinlargepiecesofcodecanbereplacedwithasimplecalltothecreatedFacade,leadingnotonlytolesscoderepetition,butalsohelpingustoincreasethereadabilityoftheimplementation.SincetheFacademethodsareusuallynamedbythehigher-levelapplicationconceptsthattheyencapsulate,theresultingcodeisalsoeasiertounderstand.ThesimplifiedAPIthataFacadeprovidesthroughitsconvenientmethods,leadstoanimplementationthatiseasiertouse,understand,andalsowriteunittestsfor.

Moreover,havingFacadestoabstractcompleximplementationsprovesitsusefulnessincaseswherethereisaneedtointroduceachangetothebusinesslogicoftheimplementation.IncaseaFacadehasawell-designedAPIwithapredictionforfuturerequirements,suchchangescanoftenrequiremodificationsjusttotheFacade’scode,leavingtherestoftheapplication’simplementationuntouchedandfollowingtheSeparationofConcernsprinciple.

Inthesamemanner,usingFacadestoabstracttheAPIofathird-partylibrarytobettermatchtheneedsofeachapplication,providesadegreeofdecouplingbetweenourcodeandtheusedlibrary.Incasethethird-partylibrarychangesitsAPIorneedstobereplacedwithanotherone,thedifferentmodulesoftheapplicationwillnotneedtoberewritten,sincetheimplementationchangeswouldbelimitedtothewrapperFacade.Inthiscase,allthatisneededistoprovideanequivalentimplementationusingthenewlibraryAPIwhilekeepingtheFacade’sAPIintact.

Page 166: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

Asanexampleoforchestratingmethodcallsandusingsensibledefaultsforspecificusecases,takealookatthefollowingsampleimplementation:

functiondo(x,y){

varz=y-x/2;

varyy=Math.pow(y,2);

varb=3*Math.random();//addsomerandomnesstotheresult

vari=0;//forthiscase

returnLibraryA.doingMethod(x,z,i,yy,b);

}

Page 167: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 168: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

HowitisadoptedbyjQueryAverylargepartofthejQueryimplementationisdedicatedtoprovidingsimpler,shorter,andmoreconvenient-to-usemethodsforthingsthatthedifferentJavaScriptAPIsalreadyallowustoachieve,butwithmorelinesofcodeandeffort.BytakingalookattheprovidedAPIsofjQuery,wecandistinguishsomegroupsofrelatedmethods.Thisgroupingcanalsobeseeninthewayinwhichthesourcecodeisstructured,placingmethodsforrelatedAPIsneartoeachother.

EvenifthewordFacadedoesnotappearinjQuery’ssourcecode,theuseofthispatterncanbewitnessedbythewayinwhichtherelatedmethodsaredefinedontheexposedjQueryobject.Mostofthetime,therelatedmethodsthatformagroupareimplementedanddefinedaspropertiesonanObjectLiteralandthenattachedtothejQueryobjectwithasinglecalltothe$.extend()orthe$.fn.extend()method.Asyoumightremember,fromthebeginningofthischapter,thismatchesalmostexactlywiththeimplementationthatComputerSciencecommonlyusestodescribehowaFacadeisimplemented,withtheexceptionthat,inJavaScript,wecancreateaplainobjectwithoutneedingtofirstdefineaclass.Asaresult,jQueryitselfcanbeseenasacollectionofFacades,whereeachoneindependentlyaddsgreatvaluetothelibrarywiththeAPIofconvenientmethodsthatitprovides.

NoteFormoreinformationon$.extend()and$.fn.extend(),youcanvisithttp://api.jquery.com/jQuery.extend/andhttp://api.jquery.com/jQuery.fn.extend/.

SomeoftheabstractedAPIgroupsthatarebigpartsofthejQueryimplementationandplayacriticalroletoitsadoptionareasfollows:

TheDOMTraversalAPITheAJAXAPITheDOMManipulationAPITheEffectsAPI

Also,agreatexampleofhowthispatterncanbeusedtoprovidesimplifiedAPIsisjQuery’sEventsAPI,whichprovidesavarietyofconvenientmethodsforthemostcommonusecasesthatareeasiertousethantherespectiveplainJavaScriptAPIs.

Page 169: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

ThejQueryDOMTraversalAPIAtthetimethatjQuerywasreleased,webdeveloperscouldlocatespecificDOMelementsofapageonlybyusingtheverylimitedgetElementById()andgetElementsByTagName()methods,sinceothermethods,suchasgetElementsByClassName(),werenotwidelysupportedbytheexistingbrowsers.ThejQueryteamrealizedhowthewebdevelopmentcouldbeleveragediftherewasasimpleAPIthatwouldeasesuchDOMtraversals,whichwouldworkthesamewayacrossallbrowsers,beaseffectiveasthefamiliarCSSSelectors,anddidtheirbesttomakesuchanimplementationareality.

TheresultofthiseffortisthenowfamousjQueryDOMTraversalAPIthatisexposedthroughthe$()function,whichplayedaseriousroleinthestandardizationofthequerySelectorAll()methodaspartoftheLevel2SelectorAPI.TheimplementationunderthehoodusesthemethodsprovidedbytheDOMAPIandcountsabout2,135linesofcodeinjQueryv2.2.0,whileitisevenbiggerinthev1.xversionsthatneededtosupportolderbrowsersaswell.Aswesawinthischapter,becauseofitscomplexitythisimplementationisnowpartofaseparatestand-aloneprojectthatisnamedSizzle.

NoteFormoreinformationonSizzleandthequerySelectorAll()method,youcanvisithttps://github.com/jquery/sizzleandhttps://developer.mozilla.org/en-US/docs/Web/API/document/querySelectorAll.

Regardlessofitscompleximplementation,theexposedAPIsarequiteeasytouse,mostlyusingsimpleCSSSelectorsasstringparameters,makingitanexcellentexampleofhowaFacadecanbeusedtocompletelyhidethecomplexityofitsinnerworkingsandexposeaconvenientAPI.SinceSizzle’sAPIisstillquitecomplex,thejQuerylibraryactuallywrapsitwithitsownAPIactingasanextraFacadelevel:

//Line733

functionSizzle(selector,context,results,seed){/*...*/}

//Line2678

jQuery.find=Sizzle;

ThejQuerylibraryfirstkeepsareferenceofSizzletotheinternaljQuery.find()methodandthenusesittoimplementallitsexposedDOMTraversalmethods,whichworkonCompositeObjectssuchas$.fn.find():

//Line2769

jQuery.fn.extend({

find:function(selector){

/*15linesofcode*/

for(i=0;i<len;i++){

jQuery.find(selector,self[i],ret);

}

/*3linesofcode*/

returnret;

}

Page 170: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

});

Finally,thefamous$()functioncanactuallybeinvokedinseveralways,butevenwhenitisinvokedwithaCSSSelectorasastringparameter,itactuallyhasanextralevelofhiddencomplexity:

//Line71

jQuery=function(selector,context){

returnnewjQuery.fn.init(selector,context);

};

//Line2825

rquickExpr=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,

//Line2735

init=jQuery.fn.init=function(selector,context,root){

/*12linesofcode*/

if(typeofselector==="string"){

if(/*...*/){

/*3linesofcode*/

}else{

match=rquickExpr.exec(selector);

}

//Matchhtmlormakesurenocontextisspecifiedfor#id

if(match&&(match[1]||!context)){

if(match[1]){

/*27linesofcode*/

//HANDLE:$(#id)

}else{

elem=document.getElementById(match[2]);

//Support:Blackberry4.6

//gEBIDreturnsnodesnolongerinthedocument(#6963)

if(elem&&elem.parentNode){

//InjecttheelementdirectlyintothejQueryobject

this.length=1;

this[0]=elem;

}

this.context=document;

this.selector=selector;

returnthis;

}

//HANDLE:$(expr,$(...))

}elseif(!context||context.jquery){

return(context||root).find(selector);

//HANDLE:$(expr,context)

//(whichisjustequivalentto:$(context).find(expr)

}else{

returnthis.constructor(context).find(selector);

}

}/*else…21linesofcode*/

};

Page 171: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

Asyoucansee,intheprecedingcode,the$()isactuallycreatinganewobjectwith$.fn.init().Insteadofbeingjustanentrypointto$.fn.find()orjQuery.find(),itisactuallyaFacadethathidesalevelofoptimization.Specifically,itmakesjQueryfasterbyavoidinginvoking$.fn.find()andSizzle,whensimpleIDselectorsareusedbydirectlyinvokingthegetElementById()method.

Page 172: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

ThepropertyaccessandmanipulationAPIAnotherveryinterestingabstractionthatfollowstheprinciplesoftheFacadePatternandcanbefoundinjQuery’ssource,isthe$.fn.prop()method.Likethe$.fn.attr(),$.fn.val(),$.fn.text(),and$.fn.html(),itbelongstoafamilyofmethodsthatischaracterizedbythefactthateachmethodisbothagetterandasetteroftherelatedsubject.Thedistinctionofthemethod’sexecutionmodeisdonebyinspectingthenumberofparametersthatarepassedduringitsinvocation.ThisconvenientAPIallowsustohavetorememberlessmethodsignaturesandmakethesettersdifferonlybyoneextraparameter.Forexample,$('#myCheckBox').prop('checked')willreturntrueorfalse,basedonthestateoftheselectedcheckbox.Ontheotherhand,$('#myCheckBox').prop('checked',true);willprogrammaticallycheckthatcheckboxforus.Inthesameconcept,$('button').prop('disabled',true);willdisableallthe<button>elementsonapage.

The$.fn.prop()methoddoesthejQueryCompositeObjecthandling,buttheactualimplementationoftheFacadeistheinternaljQuery.prop()method.AnextraconcernthataddscomplexitytotheFacade’simplementationisthefactthattherearesomeHTMLattributesthathavedifferentidentifiersforthecorrespondingpropertiesontheDOMelements:

jQuery.extend({

prop:function(elem,name,value){

/*8liesofcode*/

if(nType!==1||!jQuery.isXMLDoc(elem)){

//Fixnameandattachhooks

name=jQuery.propFix[name]||name;

hooks=jQuery.propHooks[name];

}

if(value!==undefined){

if(hooks&&"set"inhooks&&

(ret=hooks.set(elem,value,name))!==undefined){

returnret;

}

return(elem[name]=value);

}

if(hooks&&"get"inhooks&&(ret=hooks.get(elem,name))!==

null){

returnret;

}

returnelem[name];

},

propHooks:{

tabIndex:{

get:function(elem){

vartabindex=jQuery.find.attr(elem,"tabindex");

returntabindex?parseInt(tabindex,10):/*...*/;

Page 173: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

}

}

},

propFix:{

"for":"htmlFor",

"class":"className"

}

});

ThefirsthighlightedcodeareaefficientlyresolvesthepropertytoattributeidentifiermismatchbyusingthepropFixandpropHooksobjectstodothematching.ThepropFixobjectactslikeasimpledictionarytomatchtheidentifiers,whilethepropHooksobjectholdsafunctionthatdoesthematchinginaless-hard-codedway,withprogrammatictesting.Thisisagenericimplementationthatcaneasilybeextendedbyaddingextrapropertiestothosetwoobjects.

Therestofthehighlightedareasareresponsibleforthegetter/settermodeofthemethod.Theoverallimplementationistoperformthefollowingtasks:

Checkwhetheravalueispassedasanargumentand,ifthepropertyfindsthattheassignmentissuccessful,dotheassignmentandreturnthevalue.Alternatively,iftherewasnovaluepassed,returnthevalueoftherequestedpropertyifitisretrievable.

Page 174: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 175: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

UsingFacadesinourapplicationsInordertodemonstratehowfacadescanbeusedbothtoencapsulatecomplexity,helpingusenforcetheSeparationofConcernsprinciple,andalsoabstractthird-partylibraryAPIsintomoreconvenientmethodsthatareapplicationcentric,wearegoingtodemonstrateaverysimplelotteryapplication.Our“ElementLottery”applicationwillpopulateitscontainerwithsomeLotteryTicketelementsthatwillhaveauniqueIDandcontainarandomnumber.

Thewinningticketwillbepickedbyrandomlyselectingoneofthelotteryelements,basedonarandomindexamongthecreateduniqueIDs.Thewinningnumberwillthenbeannouncedtobethenumericcontentofthepickedelement.Let’sseethemodulesofourapplication:

(function(){

window.elementLottery=window.elementLottery||{};

varelementIDs;

var$lottery;

varticketCount=30;

elementLottery.init=function(){

elementIDs=[];

$lottery=$('#lottery').empty();

elementLottery.add(ticketCount);

$('#lotteryTicketButton').on('click',elementLottery.pick);

};

elementLottery.add=function(n){

for(vari=0;i<n;i++){

varid=this.uidProvider.get();

elementIDs.push(id);

$lottery.append(this.ticket.createHtml(id));

}

};

Page 176: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

elementLottery.pick=function(){

varindex=Math.floor(Math.random()*elementIDs.length);

varresult=$lottery.find('#'+elementIDs[index]).text();

alert(result);

returnresult;

};

$(document).ready(elementLottery.init);

})();

ThemainelementLotterymoduleofourapplicationinitializeditselfrightafterthepagewasfullyloaded.Theaddmethodisusedtopopulatethelotterycontainerelementwithtickets.ItusestheuidProvidersubmoduletogenerateuniqueidentifiersfortheticketelements,keepstrackofthemontheelementIDsarray,usestheticketsubmoduletoconstructtheappropriateHTMLcode,andfinallyappendstheelementtothelottery.Thepickmethodisusedtorandomlyselectthewinningticketbyrandomlyselectingoneofthegeneratedidentifiers,retrievingthepageelementwiththatID,anddisplayingitscontentinsideanalertboxasthewinningresult.ThepickmethodistriggeredbyclickingonthebuttonthatwehaveaddedanObserverduringtheinitializationphase:

(function(){

elementLottery.ticket=elementLottery.ticket||{};

elementLottery.ticket.createHtml=function(id){

varticketNumber=Math.floor(Math.random()*1000*10);

return'<divid="'+id+'"class="ticket">'+ticketNumber+

'</div>';

};

})();

(function(){

elementLottery.uidProvider=elementLottery.uidProvider||{};

elementLottery.uidProvider.get=function(){

return'Lot'+simpleguid.getNext();

};

})();

TheticketsubmobuleactsasaFacadewithasinglemethodthatisusedtoencapsulatethegenerationofarandomnumberandthecreationoftheHTMLcodethatwillbeusedastheticket.Ontheotherhand,theuidProvidesubmoduleisaFacadethatprovidesasinglegetmethodthatencapsulatesthewayweusethesimpleguidmodulethatwesawinthepreviouschapters.Asaresult,wecaneasilychangethelibrarythatisusedtogenerateuniqueidentifiersandtheonlyplacethatwewillhavetomodifytheexistingimplementationwillbetheuidProvidesubmodule.Forexample,let’sseehowitwilllookifwedecidedtousethegreatnode-uuidlibrarythatgenerates128-bituniqueidentifiersasstringsofhexadecimalcharacters:

(function(){

elementLottery.uidProvider=elementLottery.uidProvider||{};

Page 177: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

elementLottery.uidProvider.get=function(){

returnuuid.v4();

};

})();

NoteFormoreinformationonthenode-uuilibrary,youcanvisithttps://github.com/broofa/node-uuid.

Page 178: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 179: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

SummaryInthischapter,welearnedwhataFacadeactuallyis.Welearneditsphilosophyandtheuniformwayinwhichitdefineshowcodeabstractionsshouldbecreatedsothattheyareeasilyunderstandableandreusablebyotherdevelopers.

Startingfromthesimplestusecasesofthispattern,welearnedhowtowrapacomplexAPIwithaFacadeandexposeasimpleronethatisfocusedontheneedsofourapplicationandisabettermatchtoitsspecificusecases.WealsosawhowjQueryembracestheconceptsofthispatterninitsimplementationandhowprovidingsimpleAPIsformorebasicweb-developingtechniques,suchasDOMTraversals,playedacriticalroleforitswideadoption.

NowthatwehavecompletedourintroductiontohowtheFacadePatterncanbeusedtodecoupleandabstractpartsofanimplementation,wecanmoveontothenextchapterwherewewillbeintroducedtotheBuilderandFactoryPatterns.Inthenextchapter,wewilllearnhowtousethesetwoCreationalDesignPatternstoabstracttheprocessofgeneratingandinitializingnewobjectsforspecificusecasesandanalyzehowtheiradoptioncanbenefitourimplementations.

Page 180: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 181: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

Chapter6.TheBuilderandFactoryPatternsInthischapter,wewillshowcasetheBuilderandFactoryPatterns,twoofthemostcommonlyusedCreationalDesignPatterns.Thesetwodesignpatternshavesomesimilaritieswitheachother,sharesomecommongoals,andarededicatedtoeasingthecreationofcomplexresults.Wewillanalyzethebenefitsthattheiradoptioncanbringtoourimplementationsandalsothewaysinwhichtheydiffer.Finally,wewilllearnhowtousethemproperlyandchoosethemostappropriateoneforthedifferentusecasesofourimplementations.

Inthischapter,wewill:

IntroducetheFactoryPatternSeehowtheFactoryPatternisusedbyjQueryHaveanexampleoftheFactoryPatteninajQueryapplicationIntroducetheBuilderPatternComparetheBuilderandFactoryPatternsSeehowtheBuilderPatternisusedbyjQueryHaveanexampleoftheBuilderPatteninajQueryapplication

Page 182: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

IntroducingtheFactoryPatternTheFactoryPatternispartofthegroupofCreationalPatternsandoverallitdescribesagenericwayforobjectcreationandinitialization.Itiscommonlyimplementedasanobjectorfunctionthatisusedtogenerateotherobjects.AccordingtothemajorityofComputerScienceresources,thereferenceimplementationoftheFactoryPatternisdescribedasaclassthatprovidesamethodthatreturnsnewlycreatedobjects.Thereturnedobjectsarecommonlytheinstancesofaspecificclassorsubclass,ortheyexposeasetofspecificcharacteristics.

ThekeyconceptoftheFactorypatternistoabstractthewayanobjectoragroupofrelatedobjectsarecreatedandinitializedforaspecificpurpose.Thepointofthisabstractionistoavoidcouplinganimplementationwithspecificclassesorthewaythateachobjectinstanceneedstobecreatedandconfigured.Theresultisanimplementationthatworksasanabstractwayforobjectcreationandinitialization,whichfollowstheconceptofSeparationofConcerns.

Theresultingimplementationsareonlybasedontheobjectmethodsandpropertiesthatarerequiredbytheiralgorithmorbusinesslogic.Suchanapproachcanbenefitthemodularityandextensibilityofanimplementation,byfollowingtheconceptofprogrammingoverObjectFeaturesandFunctionalityinsteadofObjectClasses.Thisgivesustheflexibilitytochangetheusedclasseswithanyotherobjectthatexposesthesamefunctionality.

Page 183: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

HowitisadoptedbyjQueryAswehavealreadynotedintheearlierchapters,oneoftheearlygoalsofjQuerywastoprovideasolutionthatworkedthesameacrossallbrowsers.The1.12.xversionseriesofjQueryarefocusedonprovidingsupportforbrowsersasoldasInternetExplorer6(IE6),whilemaintainingthesameAPIwiththenewerv2.2.xversionsthatonlyfocusonmodernbrowsers.

Inordertohaveasimilarstructureandmaximizethecommoncodebetweenthetwoversions,thejQueryteamtriedtoabstractmostcompatibilitymechanismsinadifferentimplementationlayer.Suchadevelopmentpracticegreatlyimprovesthereadabilityofthecodeandreducesthecomplexityofthemainimplementation,encapsulatingitintodifferentsmallerpieces.

AgreatexampleofthisistheimplementationoftheAJAX-relatedmethodsthatjQueryprovides.Specifically,inthefollowingcode,youcanfindapartofit,asfoundinversion1.12.0ofjQuery:

//Createtherequestobject

//(ThisisstillattachedtoajaxSettingsforbackwardcompatibility)

jQuery.ajaxSettings.xhr=window.ActiveXObject!==undefined?

//Support:IE6-IE8

function(){

//XHRcannotaccesslocalfiles,alwaysuseActiveXforthatcase

if(this.isLocal){

returncreateActiveXHR();

}

//Support:IE9-11

if(document.documentMode>8){

returncreateStandardXHR();

}

//Support:IE<9

return/^(get|post|head|put|delete|options)$/i.test(this.type)&&

createStandardXHR()||createActiveXHR();

}:

//Forallotherbrowsers,usethestandardXMLHttpRequestobject

createStandardXHR;

//Functionstocreatexhrs

functioncreateStandardXHR(){

try{

returnnewwindow.XMLHttpRequest();

}catch(e){}

}

functioncreateActiveXHR(){

try{

returnnewwindow.ActiveXObject("Microsoft.XMLHTTP");

}catch(e){}

}

Page 184: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

EverytimeanewAJAXrequestisissuedonjQuery,thejQuery.ajaxSettings.xhrmethodisusedasaFactorythatcreatesanewinstanceoftheappropriateXHRobjectbasedonthesupportofthecurrentbrowser.Lookinginmoredetail,wecanseethatthejQuery.ajaxSettings.xhrmethodorchestratestheuseoftwosmallerFactoryfunctions,witheachresponsibleforaspecificimplementationofAJAX.Moreover,wecanseethatitactuallytriestoavoidrunningthecompatibilitytestsoneverycallbydirectlywiringupitsreferencetothesmallercreateStandardXHRFactoryfunctionwhenappropriate.

Page 185: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

UsingFactoriesinourapplicationsAsanexampleusecaseofFactories,wewillcreateadata-drivenformwhereouruserswillbeabletofillsomefieldsthataredynamicallycreatedandinsertedintothepage.Wewillassumetheexistenceofanarraycontainingobjectsthatdescribeeachformfieldthatneedstobepresented.OurFactorymethodwillencapsulatethewayinwhicheachformfieldneedstobeconstructed,andproperlyhandleeachspecificcase,basedonthecharacteristicsdefinedontherelatedobjects.

TheHTMLcodeforthispageisquitesimple:

<h1>DataDrivenForm</h1>

<form></form>

<scripttype="text/javascript"src="jquery.js"></script>

<scripttype="text/javascript"src="datadrivenform.js"></script>

Itonlycontainsan<h1>elementwiththepageheadingandanempty<form>elementthatwillhostthegeneratedfields.AsfortheCSSused,weonlystylethe<button>elementsinthesamewayaswedidinthepreviouschapters.

AsfortheJavaScriptimplementationoftheapplication,wecreateamoduleanddeclare

Page 186: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

dataDrivenFormasthenamespaceofthisexample.Thismodulewillcontainthedatathatdescribesourform,theFactorymethodthatwillgeneratetheHTMLofeachformelementand,ofcourse,theinitializationcodethatwillcombinetheaforementionedpartstocreatetheresultingform:

(function(){

'usestrict';

window.dataDrivenForm=window.dataDrivenForm||{};

dataDrivenForm.formElementHTMLFactory=function(type,name,title){

if(!title||!title.length){

title=name;

}

vartopPart='<div><label><span>'+title+':</span><br/>';

varbottomPart='</label></div>';

if(type==='text'){

returntopPart+

'<inputtype="text"maxlength="200"name="'+name+'"/>'+

bottomPart;

}elseif(type==='email'){

returntopPart+

'<inputtype="email"requiredname="'+name+'"/>'+

bottomPart;

}elseif(type==='number'){

returntopPart+

'<inputtype="number"min="0"max="2147483647"'+'name="'+name+

'"/>'+

bottomPart;

}elseif(type==='date'){

returntopPart+

'<inputtype="date"min="1900-01-01"name="'+

name+'"/>'+

bottomPart;

}elseif(type==='textarea'){

returntopPart+

'<textareacols="30"rows="3"maxlength="800"name="'+name+'"

/>'+

bottomPart;

}elseif(type==='checkbox'){

return'<div><label><span>'+title+':</span>'+

'<inputtype="checkbox"name="'+name+'"/>'+

'</label></div>';

}elseif(type==='notice'){

return'<p>'+name+'</p>';

}elseif(type==='button'){

return'<buttonname="'+name+'">'+title+'!</button>';

}

};

})();

OurFactorymethodwillbeinvokedwiththreeparameters.Startingfromthemostimportantone,itacceptsthetypeandthenameoftheformfieldandalsothetitlethatwillbeusedasitsdescription.Sincemostformfieldssharesomecommoncharacteristics,

Page 187: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

liketheirtitle,theFactorymethodtriestoabstracttheminordertohavelesscoderepetition.Asyoucansee,theFactorymethodalsocontainssomesensibleextraconfigurationforeachfieldtype,likethemaxlengthattributeofthetextfields,thatisspecificforthisusecase.

TheobjectstructurethatwillbeusedtorepresenteachformelementwillbeaplainJavaScriptobjectthathasatype,name,andtitleproperty.ThecollectionofobjectsthatdescribetheformfieldswillbegroupedinanarrayandbeavailableonthedataDrivenForm.partspropertyofourmodule.Inareal-worldapplication,thesefieldswouldcommonlyeitherberetrievedwithanAJAXrequestorbeinjectedintosomepartoftheHTMLofthepage.Inthefollowingcodesnippet,wecanseethedatathatwillbeusedtodrivethecreationofourform:

dataDrivenForm.parts=[{

type:'text',

name:'firstname',

title:'FirstName'

},{

type:'text',

name:'lastname',

title:'LastName'

},{

type:'email',

name:'email',

title:'e-mailaddress'

},{

type:'date',

name:'birthdate',

title:'Dateofbirth'

},{

type:'number',

name:'experience',

title:'Yearsofexperience'

},{

type:'textarea',

name:'summary',

title:'Summary'

},{

type:'checkbox',

name:'receivenotifications',

title:'Receivenotificatione-mails'

},{

type:'notice',

name:'Byusingthisformyouacceptthetermsofuse'

},{

type:'button',

name:'save'

},{

type:'button',

name:'submit'

}];

Finally,wedefineandimmediatelyinvokeaninitmethodforourmodule:

Page 188: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

dataDrivenForm.init=function(){

for(vari=0;i<dataDrivenForm.parts.length;i++){

varpart=dataDrivenForm.parts[i];

varelementHTML=dataDrivenForm.formElementHTMLFactory(part.type,

part.name,part.title);

//checkiftheresultisnull,undefinedoremptystring

if(elementHTML&&elementHTML.length){

$('form').append(elementHTML);

}

}

};

$(document).ready(dataDrivenForm.init);

TheinitializationcodewaitsuntiltheDOMofthepageisfullyloadedandthenusestheFactorymethodtocreatetheformelementsandattachthemtothe<form>elementofourpage.AnextraconcernoftheprecedingcodeistochecktheresultoftheFactorymethodinvocationbeforeactuallystartingtouseit.

MostFactories,wheninvokedwithparametersforacasetheycan’thandle,returnnulloremptyobjects.Asaresult,it’sagoodcommonpractice,whenusingFactories,tocheckwhethertheresultofeachinvocationisactuallyvalid.

Asyoucansee,havingFactoriesthatacceptonlysimpleparameters(forexample,stringsandnumbers),inmanycases,leadstoanincreasednumberofparameters.Eventhoughtheseparametersmayonlybeusedinspecificcases,theAPIofourFactorystartstobeawkwardlylongandneedsproperdocumentationforeachspecialcaseinordertobeusable.

Ideally,aFactorymethodshouldacceptasfewargumentsaspossible,otherwiseitwillstartlookinglikeaFacadethatonlyprovidesadifferentAPI.Since,insomecases,usingasinglestringornumericargumentdoesnotsuffice,inordertoavoidusingahugenumberofparameters,wecanfollowapracticewheretheFactoryisdesignedtoacceptasingleobjectasitsparameter.

Forexample,inourcase,wecanjustpassthewholeobjectthatdescribestheformfieldasaparametertotheFactorymethod:

dataDrivenForm.formElementHTMLFactory=function(formElementDefinition){

vartopPart='<div><label><span>'+formElementDefinition.title+':

</span><br/>';

varbottomPart='</label></div>';

if(formElementDefinition.type==='text'){

returntopPart+

'<inputtype="text"maxlength="200"name="'

+formElementDefinition.name+'"/>'+

bottomPart;

}/*...*/

};

Thispracticeissuggestedforthefollowingcases:

WhenwecreategenericFactoriesthatarenotfocusedonspecificusecasesandweneedtoconfiguretheirresultsdifferentlyforeachspecificusecase.

Page 189: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

Whentheconstructedobjectshavemanyoptionalconfigurationparametersthatlargelydiffer.Inthiscase,addingthemasseparateparameterstotheFactorymethodwouldleadtoinvocationsthathaveanumberofnullarguments,dependingonwhichexactargumentweareinterestedindefining.

Anotherpractice,especiallyinJavaScriptprogramming,istocreateaFactorymethodthatacceptsasimplestringornumericvalueasitsfirstargumentandoptionallyprovideacomplementaryobjectasasecondparameter.ThisenablesustohaveasimplegenericAPIthatcanbeuse-case-specificandalsogivesussomeextrapointsoffreedomtoconfiguresomespecialcases.Thisapproachisusedbythe$.ajax(url[,settings])methodthatallowsustogeneratesimpleGETrequestsbyjustprovidingaURLandalsoacceptsanoptionalsettingsparameterthatallowsustoconfigureanyaspectoftherequest.Changingtheaboveimplementationtousethisvariationisleftasanexerciseforthereader,inordertoexperimentandgetfamiliarwiththeuseofFactorymethods.

Page 190: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 191: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

IntroducingtheBuilderPatternTheBuilderPatternispartofthegroupofCreationalPatternsandprovidesusawaytocreateobjectsthatrequirealotofconfigurationbeforetheyreachthepointwheretheycanbeused.TheBuilderPatternisoftenusedforobjectsthatacceptmanyoptionalparametersinordertodefinetheiroperation.Anothermatchingcaseisforthecreationofobjectswheretheirconfigurationneedstobedoneinseveralstepsorinaspecificorder.

ThecommonparadigmfortheBuilderPatternaccordingtoComputerScienceisthatthereisaBuilderObjectthatprovidesoneormoresettermethods(setA(...),setB(...))andasinglegenerationmethodthatconstructsandreturnsthenewlycreatedresultobject(getResult()).

Thispatternhastwoimportantconcepts.ThefirstoneisthattheBuilderObjectexposesanumberofmethodsasawaytoconfigurethedifferentpartsoftheobjectthatisunderconstruction.Duringtheconfigurationphase,theBuilderObjectpreservesaninternalstatethatreflectstheeffectsoftheinvocationsoftheprovidedsettermethods.Thiscanbebeneficialwhenusedtocreateobjectsthatacceptalargenumberofconfigurationparameters,solvingtheproblemofTelescopicConstructors.

NoteTelescopicConstructorsisananti-patternofobject-orientedprogrammingthatdescribesthesituationwhereaclassprovidesseveralconstructorsthattendtodifferonthenumber,thetype,andthecombinationoftheargumentsthattheyrequire.Objectclasseswithseveralparametersthatcanbeusedinmanydifferentcombinationscanoftenleadtoimplementationsfallingintothisanti-pattern.

Thesecondimportantconceptisthatitalsoprovidesagenerationmethodthatreturnstheactualconstructedobjectbasedontheprecedingconfiguration.Mostofthetime,theinstantiationoftherequestedobjectisdonelazilyandactuallytakesplaceatthemomentthatthismethodisinvoked.Insomecases,theBuilderObjectallowsustoinvokethegenerationmethodmorethanonce,allowingustogenerateseveralobjectswiththesameconfiguration.

Page 192: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

HowitisadoptedbyjQuery’sAPITheBuilderPatterncanalsobefoundaspartoftheAPIthatjQueryexposes.Specifically,thejQuery$()functioncanalsobeusedtocreatenewDOMelementsbyinvokingitwithanHTMLstringasanargument.Asaresult,wecancreatenewDOMelementsandsettheirdifferentpartsasweneedthem,insteadofhavingtocreatetheexactHTMLstringthatisneededforthefinalresult:

var$input=$('<input/>');

$input.attr('type','number');

$input.attr('min','0');

$input.attr('max','100');

$input.prop('required',true);

$input.val(4);

$input.appendTo('form');

The$('<input/>')callreturnsaCompositeObjectcontaininganelementthatisnotattachedtotheDOMtreeofthepage.Thisunattachedelementisonlyanin-memoryobjectthatisneitherfullyconstructednorfullyfunctionaluntilweattachittothepage.Inthiscase,thisCompositeObjectactslikeaBuilderObjectInstancehavinganinternalstateofobjectsthatarenotyetfinalized.Rightafterthis,wedoaseriesofmanipulationsonitusingsomejQuerymethodsthatactlikethesettermethodsdescribedbytheBuilderPattern.

Finally,afterweapplyalltherequiredconfigurations,sothattheresultingobjectbehavesinthedesiredway,weinvokethe$.fn.appendTo()method.The$.fn.appendTo()methodworksasthegenerationmethodoftheBuilderPattern,byattachingthein-memoryelementofthe$inputvariabletotheDOMtreeofthepage,transformingitintoanactualattachedDOMelement.

Ofcourse,theaboveexamplecangetmorereadableandlessrepetitivebyutilizingtheFluentAPIthatjQueryprovidesforitsmethods,andalsocombinethe$.fn.attr()methodinvocations.Moreover,jQueryallowsustousealmostallitsmethodstodotraversalsandmanipulationsontheelementsthatareunderconstruction,justaswecanonnormalDOMelementCompositeObjects.Asaresult,theaboveexamplecangetalittlemorecompleteasfollows:

$('<input/>').attr({

'type':'number',

'min':'0',

'max':'100'

})

.prop('required',true)

.val(4)

.css('display','block')

.wrap('<label>')//wraptheinputwitha<label>

.parent()//traverseonelevelup,tothe<label>

.prepend('<span>Qty:#</span')

.appendTo('form');

Page 193: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

Theresultwilllookasfollows:

Thecriteriathatallowustocategorizethisoverloadedwayofinvokingthe$()functionasanimplementationthatadoptstheBuilderPattern,isthefactthat:

Itreturnsanobjectwithaninternalstatecontainingpartiallyconstructedelements.Thecontainedelementsareonlyin-memoryobjectsthatarenotpartofthepage’sDOMtree.Itprovidesusmethodstomanipulateitsinternalstate.MostjQuerymethodscanbeusedforthispurpose.Itprovidesusmethod(s)togeneratethefinalresult.WecanusejQuerymethodssuchas$.fn.appendTo()and$.fn.insertAfter(),asawaytocompletetheconstructionoftheinternalelementsandmakethempartoftheDOMtreewithpropertiesthatreflecttheirearlierin-memoryrepresentation.

AswehavealreadyseeninChapter1,ARefresheronjQueryandtheCompositePattern,theprimarywaytousethe$()functionistoinvokeitwithaCSSselectorasastringparameterandinturnitwillretrievethematchingpageelementsandreturntheminaCompositeObject.Ontheotherhand,whenthe$()functiondetectsthatithasbeeninvokedwithastringparameterthatlookslikeapieceofHTML,itworksasaDOMelementBuilder.Thisoverloadedwayofinvokingthe$()functionbasesitsdetectionontheassumptionthattheprovidedHTMLcodestartsandendswiththeinequalitysymbols<and>:

init=jQuery.fn.init=function(selector,context){

/*11linesofcode*/

//HandleHTMLstrings

if(typeofselector==="string"){

if(selector[0]==="<"&&selector[selector.length-1]===">"

&&selector.length>=3){

//Assumethatstringsthatstartandendwith<>areHTML//and

skiptheregexcheck

match=[null,selector,null];

}/*...*/

//Matchhtmlormakesurenocontextisspecifiedfor#id

if(match&&(match[1]||!context)){

//HANDLE:$(html)->$(array)

Page 194: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

if(match[1]){

/*4linesofcode*/

jQuery.merge(this,jQuery.parseHTML(match[1],/*...*/));

/*16linesofcode*/

returnthis;

}/*...*/

}/*...*/

}/*...*/

};

Aswecanseeintheprecedingcode,thisoverloadusesthejQuery.parseHTML()helpermethodthatultimatelyleadstoacallofthecreateDocumentFragment()method.ThecreatedDocumentFragmentisthenusedasahostoftheunderconstructiontreestructureofelements.AfterjQueryfinishesconvertingtheHTMLintoelements,theDocumentFragmentisdiscardedandonlyit’shostedelementsarereturned:

jQuery.parseHTML=function(data,context,keepScripts){

/*17linesofcode*/

//Singletag

if(parsed){

return[context.createElement(parsed[1])];

}

parsed=buildFragment([data],context,scripts);

/*5linesofcode*/

returnjQuery.merge([],parsed.childNodes);

};

ThisresultsinthecreationofanewjQueryCompositeObjectcontaininganin-memorytreestructureofelements.EventhoughtheseelementsarenotattachedtotheactualDOMtreeofthepage,wecanstilldotraversalsandmanipulationsonthemlikeanyotherjQueryCompositeObject.

NoteFormoreinformationonDocumentFragments,youcanvisit:https://developer.mozilla.org/en-US/docs/Web/API/Document/createDocumentFragment.

Page 195: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

HowitisusedbyjQueryinternallyAnundoubtedlybigpartofjQueryisitsAJAX-relatedimplementation,whichaimstoprovideasimpleAPIforasynchronouscallsthatisalsoconfigurabletoalargedegree.UsingthejQuerySourceViewerandsearchingforjQuery.ajax,ordirectlysearchingjQuery’ssourcecodefor"ajax:",willbringustheaforementionedimplementation.Inordertomakeitsimplementationmorestraightforwardandalsoallowittobeconfigurable,jQueryinternallyusesaspecialobjectstructurethatactsasaBuilderObjectforthecreationandhandlingofeachAJAXrequest.Aswewillsee,thisisnotthemostcommonwayofusingaBuilderObject,butitisactuallyaspecialvariantwithsomemodificationsinordertofittherequirementsofthiscompleximplementation:

jqXHR={

readyState:0,

//Buildsheadershashtableifneeded

getResponseHeader:function(key){/*...*/},

//Rawstring

getAllResponseHeaders:function(){/*...*/},

//Cachestheheader

setRequestHeader:function(name,value){/*...*/},

//Overridesresponsecontent-typeheader

overrideMimeType:function(type){/*...*/},

//Status-dependentcallbacks

statusCode:function(map){/*...*/},

//Canceltherequest

abort:function(statusText){/*...*/}

};

ThemainmethodthatthejqXHRobjectexposestoconfigurethegeneratedasynchronousrequestisthesetRequestHeader()method.Theimplementationofthismethodisquitegeneric,enablingjQuerytosetallthedifferentHTTPheadersfortherequest,usingonlyonemethod.

Inordertoprovideanevengreaterdegreeofflexibilityandabstraction,jQueryinternallyusesaseparatetransportobjectasawrapperofthejqXHRobject.ThistransportobjecthandlesthepartofactuallysendingtheAJAXrequesttotheserver,workinglikeapartnerbuilderobjectthatcooperateswiththejqXHRobjectforthecreationofthefinalresult.Thisway,jQuerycanfetchScripts,XML,JSON,andJSONPresponsesfromthesameorcross-originservers,usingthesameAPIandoverallimplementation:

transport=inspectPrefiltersOrTransports(transports,s,options,jqXHR);

//Ifnotransport,weauto-abort

if(!transport){

done(-1,"NoTransport");

}else{

Page 196: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

jqXHR.readyState=1;

/*12linesofcode*/

try{

state=1;

transport.send(requestHeaders,done);

}catch(e){/*7linesofcode*/}

}

AnotherspecialthingaboutthisimplementationoftheBuilderPatternisthatitshouldbeabletooperateinbothsynchronousandasynchronousmanner.Asaresult,thesend()methodofthetransportobjectthatactsastheresultgeneratormethodofthewrappedjqXHRobjectcan’tjustreturnaresultobject,butitisinsteadinvokedwithacallback.

Finally,aftertherequestiscomplete,jQueryusesthegetResponseHeader()methodtoretrievealltherequiredresponseheaders.Rightafterthis,theheadersareusedtoproperlyconvertthereceivedresponsethatisstoredintheresponseTextpropertyofthejqXHRobject.

Page 197: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

HowtouseitinourapplicationsAsanexampleusecaseoftheBuilderPatterninaclient-sideapplicationthatusesjQuery,wewillcreateasimpledata-drivenmultiple-choicequiz.ThemainreasonthattheBuilderPatternisabettermatchforthiscase,ascomparedtotheFactoryPatternexamplethatwesawearlier,isthattheresultismorecomplexandhasmoredegreesofconfiguration.Eachquestionwillbegeneratedbasedonamodelobjectthatwillrepresentitsdesiredproperties.

Onceagain,therequiredHTMLisverysimple,containingjustan<h1>elementwiththeheaderofthepage,anempty<form>tag,andsomereferencestoourCSSandJavaScriptresources:

<h1>DataDrivenQuiz</h1>

<form></form>

<scripttype="text/javascript"src="jquery.js"></script>

<scripttype="text/javascript"src="datadrivenquiz.js"></script>

Besidesthecommon,simplestylesthatwehaveseeninthepreviouschapters,theCSSof

Page 198: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

thisexampleadditionallydefines:

ul.unstyled>li{

margin:0;

padding:0;

list-style:none;

}

Fortheneedsofthisexample,wewillcreateamodulewithanewnamespacenameddataDrivenQuiz.Aswesawearlierinthischapter,wewillassumetheexistenceofanarraycontainingthemodelobjectsthatdescribeeachmultiple-choicequestionthatneedstobepresented.Eachofthesemodelobjectswillhave:

AtitlepropertythatwillholdthequestionAnoptionspropertythatwillbeanarraywiththeavailableanswerstochoosefromAnoptionalacceptsMultiplepropertytosignifywhetherweshoulduseradioorcheckboxes

ThearraywiththemodelobjectsthatdescribetheformquestionswillbeavailableatthedataDrivenQuiz.partspropertyofourmodule,whilekeepinginmindthatourimplementationcouldeasilybemodifiedtofetchthemodelswithanAJAXrequest:

dataDrivenQuiz.questions=[{

title:'WhichisthemostpreferredwaytowriteourJavaScriptcode?',

options:[

'inlinealongwithourHTML',

'flatinside*.jsfiles',

'insmallModules,oneper*.jsfile'

]

},{

title:'Whatdoesthe$()functionreturnswheninvokedwithaCSS

selector?',

options:[

'asingleelement',

'anarrayofelements',

'theHTMLoftheselectedelement',

'aCompositeObject'

]

},{

title:'WhichofthefollowingareDesignPatterns',

acceptsMultiple:true,

options:[

'GarbageCollector',

'Class',

'ObjectLiteral',

'Observer'

]

},{

title:'Howcangetaholdtothe<body>elementofapage?',

acceptsMultiple:true,

options:[

'document.body',

'document.getElementsByTagName(\'body\')[0]',

'$(\'body\')[0]',

Page 199: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

'document.querySelector(\'body\')'

]

}];

TipDefiningthedatastructuresthatarerequiredtodescribeaproblem,beforestartingtheactualimplementation,allowsustofocusontheneedsoftheapplicationandgetanestimateofitsoverallcomplexity.

Giventheprecedingsampledata,let’snowproceedtotheimplementationofourBuilder:

functionMultipleChoiceBuilder(){

this.title='Untitled';

this.options=[];

}

dataDrivenQuiz.MultipleChoiceBuilder=MultipleChoiceBuilder;

MultipleChoiceBuilder.prototype.setTitle=function(title){

this.title=title;

returnthis;

};

MultipleChoiceBuilder.prototype.setAcceptsMultiple=

function(acceptsMultiple){

this.acceptsMultiple=acceptsMultiple;

returnthis;

};

MultipleChoiceBuilder.prototype.addOption=function(title){

this.options.push(title);

returnthis;

};

MultipleChoiceBuilder.prototype.getResult=function(){

var$header=$('<header>').text(this.title||'Untitled');

varquestionGuid='quizQuestion'+(jQuery.guid++);

var$optionsList=$('<ulclass="unstyled">');

for(vari=0;i<this.options.length;i++){

var$input=$('<input/>').attr({

'type':this.acceptsMultiple?'checkbox':'radio',

'value':i,

'name':questionGuid,

});

var$option=$('<li>');

$('<label>').append($input,$('<span>').text(this.options[i]))

.appendTo($option);

$optionsList.append($option);

}

return$('<article>').append($header,$optionsList);

};

UsingthePrototypicalObject-OrientedapproachofJavaScript,wefirstlydefinetheConstructorFunctionforourMultipleChoiceBuilderclass.WhentheConstructor

Page 200: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

Functionisinvokedusingthenewoperator,itwillcreateanewinstanceoftheBuilderandinitializeitstitlepropertyto"Untitled"andtheoptionspropertytoanemptyarray.

Rightafterthis,wecompletethedefinitionoftheConstructorFunctionofourBuilder,weattachitasamemberofourmodule,andcontinuewiththedefinitionofitssettermethods.FollowingthePrototypicalClassparadigm,thesetTitle(),setAcceptsMultiple(),andaddOption()methodsaredefinedaspropertiesofourBuilder’sPrototypeandareusedtomodifytheinternalstateoftheunderconstructionelement.Additionally,inordertoenableustochainseveralinvocationsofthesemethods,whichresultsinamorereadableimplementation,allofthemendwiththereturnthis;statement.

WecompletetheimplementationoftheBuilderwiththegetResult()methodthathasthedutyofgatheringalltheparametersthatareappliedontheBuilderobjectinstanceandgeneratingtheresultingelementwrappedinsideajQueryCompositeObject.Initsfirstline,itcreatesaheaderofthequestion.Rightafterthis,itcreatesa<ul>elementwiththeunstyledCSSclasstoholdthepossibleanswerstothequestionandauniqueidentifierthatwillbeusedasthenameofthegenerated<input>ofthequestion.

Intheforloopthatfollows,wewill:

Createan<input/>elementforeachoptionofthequestionProperlysetitstypeasacheckboxoraradiobutton,basedonthevalueoftheacceptsMultiplepropertyUsetheforloop’siterationnumberasitsvalueSettheuniqueidentifierthatwegeneratedearlierforthequestionastheinput’snameinordertogrouptheanswersFinally,adda<label>withtheoption’stext,whichwrapsalloftheminsidean<li>,andappendittothequestion’s<ul>.

Lastly,theheaderandthelistofoptionsarewrappedinan<article>element,whichisthenreturnedasthefinalresultoftheBuilder.

Intheaboveimplementation,weusethe$.fn.text()methodtoassignthecontentofthequestion’sheaderanditsavailablechoicesinsteadofstringconcatenation,inordertoproperlyescapethe<and>charactersthatarefoundintheirdescriptions.Asanextranote,sincesomeoftheanswersalsocontainsinglequotes,weneedtoescapetheminthemodelobjectsusingabackslash(\').

Finally,inourmodule’simplementation,wedefineandimmediatelyinvoketheinitmethod:

dataDrivenQuiz.init=function(){

for(vari=0;i<dataDrivenQuiz.questions.length;i++){

varquestion=dataDrivenQuiz.questions[i];

varbuilder=newdataDrivenQuiz.MultipleChoiceBuilder();

builder.setTitle(question.title)

.setAcceptsMultiple(question.acceptsMultiple);

for(varj=0;j<question.options.length;j++){

builder.addOption(question.options[j]);

Page 201: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

}

$('form').append(builder.getResult());

}

};

$(document).ready(dataDrivenQuiz.init);

TheexecutionoftheinitializationcodeisdelayeduntiltheDOMtreeofthepageisfullyloaded.Thentheinit()methoditeratesoverthemodelobjectsarrayandusestheBuildertocreateeachquestionandpopulatethe<form>elementofourpage.

Agoodexerciseforthereaderwouldbetoextendtheaboveimplementationinordertosupporttheclient-sideevaluationofthequiz.Firstly,thiswouldrequireyoutoextendthequestionobjectstocontaininformationaboutthevalidityofeachchoice.Then,itwouldbesuggestedthatyoucreateaBuilderthatwouldretrievetheanswersfromtheform,evaluatethem,andcreatearesultobjectwiththeuserchoicesandtheoverallsuccessonthequiz.

Page 202: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 203: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

SummaryInthischapter,welearnedtheconceptsoftheBuilderandFactoryPatterns,twoofthemostcommonlyusedCreationalDesignPatterns.Weanalyzedtheircommongoals,theirdifferentapproachesonabstractingtheprocessofgeneratingandinitializingnewobjectsforspecificusecases,andhowtheiradoptioncanbenefitourimplementations.Finally,welearnedhowtousethemproperlyandhowtochoosethemostappropriateoneforthedifferentusecasesofanygivenimplementations.

NowthatwehavecompletedourintroductiontothemostimportantCreationalDesignPatterns,wecanmoveontothenextchapterwherewewillbeintroducedtothedevelopmentpatternsthatareusedtoprogramasynchronousandconcurrentprocedures.Inmoredetail,wewilllearnhowtoorchestratetheexecutionofasynchronousproceduresthatruneitherinorderorparalleltoeachother,byusingcallbacksandjQueryDeferredandPromisesAPIs.

Page 204: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 205: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

Chapter7.AsynchronousControlFlowPatternsThischapterisdedicatedtodevelopmentpatternsthatareusedtoeasetheprogrammingofasynchronousandconcurrentprocedures.

Atfirst,wewillhavearefresheronhowCallbacksareusedinJavaScriptprogrammingandhowtheyareanintegralpartofwebdevelopment.Wewillthenproceedandidentifytheirbenefitsandlimitationswhenusedinlargeandcompleximplementations.

Rightafterthis,wewillbeintroducedtotheconceptofPromises.WewilllearnhowjQuery’sDeferredandPromiseAPIsworkandhowtheydifferfromES6Promises.WewillseewhereandhowtheyareusedinternallybyjQuerytosimplifyitsimplementationandleadtomorereadablecode.Wewillanalyzetheirbenefits,classifythebestmatchingusecases,andcomparethemwiththeclassicCallbackPattern.

Bytheendofthischapter,wewillbeabletousejQueryDeferredandPromisestoefficientlyorchestratetheexecutionofasynchronousproceduresthatruneitherinorderorparalleltoeachother.

Inthischapter,wewill:

HavearefresheronhowCallbacksareusedinJavaScriptprogrammingGetintroducedtotheconceptofPromisesLearnhowtousejQuery’sDeferredandPromiseAPIsComparejQueryPromiseswithES6PromisesLearnhowtoorchestrateasynchronoustasksusingPromises.

Page 206: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

ProgrammingwithcallbacksACallbackcanbedefinedasafunctionthatispassedasaninvocationargumenttoanotherfunctionormethod(whichisreferredtoasaHigher-OrderFunction)andisexpectedtobeexecutedatsomelaterpointoftime.Inthisway,thepieceofcodethatwashandedourCallbackwilleventuallyinvokeit,propagatingtheresultsofanoperationoreventbacktothecontextthattheCallbackwasdefined.

Callbackscanbecharacterizedassynchronousorasynchronous,basedonthewaythattheinvokedmethodoperates.ACallbackischaracterizedassynchronouswhenitisexecutedbyablockingmethod.Ontheotherhand,JavaScriptdevelopersaremorefamiliarwithasynchronouscallbacks,alsocalleddeferredcallbacks,whicharesettobeexecutedafteranasynchronousprocedurefinishesorwhenaspecificeventoccurs(pageload,click,AJAXresponsearrival,andsoon).

CallbacksarewidelyusedinJavaScriptapplicationssincetheyareanintegralpartofmanycoreJavaScriptAPIssuchasAJAX.Moreover,JavaScriptimplementationsofthispatternarealmostwordforwordasdescribedbytheabovesimpledefinition.ThisisaresultofthewaythatJavaScripttreatsfunctionsasobjectsandallowsustostoreandpassmethodreferencesassimplevariables.

Page 207: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

UsingsimplecallbacksinJavaScriptPerhapsoneofthesimplestexamplesofasynchronouscallbacksinJavaScriptisthesetTimeout()function.Thefollowingcodedemonstratesasimpleuseofit,whereweinvokesetTimeout()withthedoLater()functionasacallbackparameterand,after1000millisecondsofwaiting,thedoLater()callbackisinvoked:

varalertMessage='Onesecondpassed!';

functiondoLater(){

alert(alertMessage);

}

setTimeout(doLater,1000);

Asseeninthesimpleprecedingexample,thecallbackisexecutedinthecontextthatitwasdefined.Thecallbackstillhasaccesstothevariablesofthecontextthatitwasdefinedbycreatingaclosure.Eventhoughtheprecedingexampleusesanamedfunctiondefinedearlier,thesameappliesforanonymouscallbacks:

varalertMessage='Onesecondpassed!';

setTimeout(function(){

alert(alertMessage);

},1000);

Inmanycases,usinganonymouscallbacksisamoreconvenientwayofprogramming,sinceitresultsinshortercodeandalsoreducesthereadabilitynoise,whichisaresultofdefiningseveraldifferentnamedfunctionsthatareusedonlyonce.

Page 208: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

SettingcallbacksasobjectpropertiesAsmallvariationoftheabovedefinitionalsoexists,wherethecallbackfunctionisassignedtoapropertyofanobjectinsteadofbeingpassedasanargumentofamethodinvocation.Thisiscommonlyusedincaseswherethereareseveraldifferentactionsthatneedtotakeplaceduringorafteramethodinvocationiscompleted:

varc=newCountdown();

c.onProgress=function(progressStatus){/*...*/};

c.onDone=function(result){/*...*/};

c.onError=function(error){/*...*/};

c.start();

Anotherusecaseoftheabovevariantistoaddhandlersonobjectsthathavealreadybeeninstantiatedandinitialized.Agoodexampleofthiscaseisthewaywesetuparesulthandlerforsimple(non-jQuery)AJAXcalls:

varr=newXMLHttpRequest();

r.open('GET','data.json',true);

r.onreadystatechange=function(){

if(r.readyState!=4||r.status!=200){

return;

}

alert(r.responseText);

};

r.send();

Intheprecedingcode,wesetananonymousfunctionontheonreadystatechangepropertyoftheXMLHttpRequestobject.Thisfunctionactsasacallbackandisinvokedeverytimethereisastatechangeontheongoingrequest.Insideourcallback,wecheckwhethertherequesthascompletedwithasuccessfulHTTPstatuscodeanddisplayanalertwiththeresponsebody.Likeinthisexample,whereweinitiatetheAJAXcallbyinvokingthesend()methodwithoutpassinganyarguments,itiscommonforAPIsthatusethisvarianttoleadtominimalwaysofinvokingtheirmethods.

Page 209: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

UsingcallbacksinjQueryapplicationsPerhapsthemostcommonwayinwhichcallbacksareusedinjQueryapplicationsisforeventhandling.Thisislogicalsincethefirstthingthateveryinteractiveapplicationshoulddoishandleandrespondtouseractions.Aswesawinearlierchapters,oneofthemostconvenientwaystoattacheventhandlerstoelementsisbyusingjQuery’s$.fn.on()method.

AnothercommonplacewherecallbacksareusedinjQueryisforAJAXrequests,wherethe$.ajax()methodhasthecentralrole.Moreover,thejQuerylibraryalsoprovidesseveralotherconvenientmethodstomakeAJAXrequeststhatarefocusedonthemostcommonusecases.Sinceallthesemethodsareexecutedasynchronously,theyalsoacceptacallbackasaparameter,asawaytomaketheretrieveddataavailablebacktothecontextthatinitiatedtheAJAXrequest.Oneoftheseconvenientmethodsis$.getJSON(),whichisawrapperaround$.ajax(),andisusedasabettermatchingAPItoexecuteAJAXrequeststhatintendtoretrieveJSONresponses.

OtherwidelyusedjQueryAPIsacceptingcallbacksareasfollows:

Theeffects-relatedjQuerymethodssuchas$.animate()The$(document).ready()method

Let’snowcontinuebydemonstratingacodeexamplewherealltheabovemethodsareused.

$(document).ready(function(){

$('#fetchButton').on('click',function(){

$.getJSON('AjaxContent.json',function(json){

console.log('doneloadingnewcontent');

$('#newContent').css({'display':'none'})

.text(json.data)

.slideDown(function(){

console.log('donedisplayingnewcontent');

});

});

});

});

TheprecedingcodefirstlydelaysitsexecutionuntiltheDOMtreeofthepagehasbeenfullyloadedandthenaddsanObserverforclicksonthe<button>withIDfetchButtonbyusingthejQuery’s$.fn.on()method.Whenevertheclickeventisfired,theprovidedcallbackwillbeinvokedandinitiateanAJAXcalltofetchtheAjaxContent.jsonfile.Fortheneedsofthisexample,weareusingasimpleJSONfile,likethefollowing:

{"data":"I'mthetextcontentfetchedbyanAJAXcall!"}

WhentheresponseisreceivedandtheJSONisparsedsuccessfully,thecallbackisinvokedwiththeparsedobjectasaparameter.Finally,thecallbackitselflocatesthepageelementwiththeIDnewContentinthepage,hidesit,andthensetsthedatafieldoftheretrievedJSONasitstextcontent.Rightafterthis,weusethejQuery$.fn.slideDown()

Page 210: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

methodthatmakesthenewlysetpagecontentappear,byprogressivelyincreasingitsheight.Finally,aftertheanimationiscomplete,wewritealogmessagetothebrowserconsole.

NoteFurtherdocumentationregardingjQuery’s$.ajax(),$.getJSON(),and$.fn.slideDown()methodscanbefoundathttp://api.jquery.com/jQuery.ajax/,http://api.jquery.com/jQuery.getJSON/,andhttp://api.jquery.com/slideDown/.

Keepinmindthatthe$.getJSON()methodmightnotworkinsomebrowserswhenthepageisloadedthroughthefilesystem,butworksasintendedwhenservedusinganywebserversuchasApache,IIS,ornginx.

Page 211: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

WritingmethodsthatacceptcallbacksWhenwritingafunctionthatutilizesoneormoreasynchronousAPIs,thatalsodictatesthattheresultingfunctionwillbeasynchronousbydefinition.Inthatcase,itisobviousthatsimplyreturningaresultvalueisnotanoption,sincetheresultwillprobablybeavailableafterthefunctioninvocationhasalreadyfinished.

Theeasiestsolutionforasynchronousimplementationsistouseacallbackasaparameterofyourfunction,which,aswediscussedearlier,ishassle-freeinJavaScript.Asanexample,wewillcreateanasynchronousfunctionthatgeneratesarandomnumberofaspecifiedrange:

functiongetRandomNumberAsync(max,callbackFn){

varrunFor=1000+Math.random()*1000;

setTimeout(function(){

varresult=Math.random()*max;

callbackFn(result);

},runFor);

}

ThegetRandomNumberAsync()functionacceptsitsmaxargumentasthenumericupperboundforthegeneratedrandomnumberandalsoacallbackfunctionthatitwillinvokewiththegeneratedresult.ItusessetTimeout()toemulateanasynchronouscalculationthatrangesfrom1000to2000milliseconds.Forthegenerationoftheresult,itusestheMath.random()method,multiplyingitwiththemaximumallowedvalue,andfinallyinvokestheprovidedcallbackwithit.Asimplewaytoinvokethisfunctionwilllookasfollows:

getRandomNumberAsync(10,function(number){

console.log(number);//returnsanumberbetween0and10

});

EventhoughtheaboveexampleusessetTimeout()toemulateasynchronousprocessing,theimplementationprinciplesremainthesameregardlessoftheasynchronousAPI(s)thatisused.Forexample,wecanrewritetheabovefunctiontoretrieveitsresultthroughanAJAXcall:

functiongetRandomNumberWS(max,callbackFn,errorFn){

$.ajax({

url:'https://qrng.anu.edu.au/API/jsonI.php?length=1&type=uint16',

dataType:'json',

success:function(json){

varresult=json.data[0]/65535*max;

callbackFn(result);

},

error:errorFn

});

}

Theprecedingimplementationusesthe$.ajax()methodthatisinvokedwithanobjectparameter,enclosingalltheoptionsoftherequest.ExceptfortheURLfortherequest,theobjectalsodefinestheexpecteddataTypeoftheresultandthesuccessanderror

Page 212: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

callbacks,whicharewiredwiththerespectiveparametersofourfunction.

Perhapstheonlyextraconcernthattheprecedingcodehastoresolveishowtohandleerrorsinsidethesuccesscallbacksothatthecallerofthefunctioncanbenotifiedincasesomethinggoeswrongduringthecreationoftheresult.Forexample,theAJAXrequestmightreturnanemptyobject.Addingproperhandlingforsuchcasesisleftasanexerciseforthereader,afterreadingtherestofthischapter.

NoteTheAustralianNationalUniversity(ANU)providesfree,trulyrandom,numberstothepublic,throughtheirRESTWebService.Formoreinformation,youcanvisithttp://qrng.anu.edu.au/API/api-demo.php.

Page 213: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

OrchestratingcallbacksWewillnowcontinuebyanalyzingsomepatternsthatarecommonlyusedtocontroltheexecutionflowwhendealingwithasynchronousmethodsthatacceptcallbacks.

QueuinginorderexecutionAsourfirstexample,wewillcreateafunctionthatdemonstrateshowwecanqueuetheexecutionofseveralasynchronoustasks:

functiongetThreeRandomNumbers(callbackFn,errorFn){

varresults=[];

getRandomNumberAsync(10,function(number){

results.push(number);

getRandomNumberAsync(10,function(number){

results.push(number);

getRandomNumberWS(10,function(number){

results.push(number);

callbackFn(results);

},function(error){

errorFn(error);

});

});

});

}

Intheprecedingimplementation,ourfunctioncreatesaqueueofthreerandomnumbergenerations.ThefirsttworandomnumbersaregeneratedfromoursamplesetTimeout()implementationandthethirdisretrievedfromtheaforementionedwebservicethoughanAJAXcall.Inthisexample,allthenumbersaregatheredintheresultarray,whichispassedasaninvocationparametertothecallbackFnafteralltheasynchronoustaskshavecompleted.

TheprecedingimplementationisquitestraightforwardandjustappliesthesimpleprinciplesoftheCallbackPatternrepeatedly.Foreveryextraorqueuedasynchronoustask,wejustneedtonestitsinvocationinsidethecallbackofthetaskthatitdependson.Keepinmindthat,indifferentusecases,wemightonlycaretoreturntheresultofthefinaltaskandhavetheresultsoftheintermediatestepsbepropagatedasargumentsforeachsubsequentasynchronouscall.

AvoidingtheCallbackHellanti-pattern

Eventhoughwritingcodeasshownintheaboveexampleiseasy,whenappliedtolargeandcompleximplementations,itcanleadtobadreadability.Thetriangularshapethatiscreatedbythewhite-spacesinfrontofourcodeandthestackingofseveral});nearitsend,arethetwosignsthatourcodemightleadtoananti-patternknownasCallbackHell.

NoteFormoreinformation,youcanvisithttp://callbackhell.com/.

Page 214: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

Awaytoavoidthisanti-patternistounfoldthenestedcallbacks,bycreatingseparatenamedfunctionsatthesamelevelwiththeasynchronoustaskthattheyareused.Afterapplyingthissimpletiptotheaboveexample,theresultingcodelooksalotcleaner:

functiongetThreeRandomNumbers(callbackFn,errorFn){

varresults=[];

getRandomNumberAsync(10,function(number){//task1

results.push(number);

task2();

});

functiontask2(){

getRandomNumberAsync(10,function(number){

results.push(number);

task3();

});

}

functiontask3(){

getRandomNumberWS(10,function(number){

results.push(number);

callbackFn(results);

},errorFn);

}

}

Asyoucansee,theresultingcodesurelydoesnotremindusofthecharacteristicsoftheCallbackHellanti-pattern.Ontheotherhand,itnowneedsmorelinesofcodeforitsimplementation,mostlyusedfortheadditionalfunctiondeclarationsfunctiontaskX(){}thatarenowrequired.

TipAmiddlegroundsolutionbetweentheabovetwoapproachesistoorganizetherelatedpartsofsuchasynchronousexecutionqueuesinsmallandmanageablefunctions.

RunningconcurrentlyEventhoughJavaScriptinwebbrowsersissingle-threaded,makingindependentasynchronoustasksrunconcurrentlycanmakeourapplicationsworkfaster.Asanexample,wewillrewritetheprecedingimplementationtofetchallthreerandomnumbersinparallel,whichcanmaketheresulttoberetrievedalotfasterthanbefore:

functiongetRandomNumbersConcurent(callbackFn,errorFn){

varresults=[];

varresultCount=0;

varn=3;

functiongatherResult(resultPos){

returnfunction(result){

results[resultPos]=result;

resultCount++;

if(resultCount===n){

Page 215: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

callbackFn(results);

}

};

}

getRandomNumberAsync(10,gatherResult(0));

getRandomNumberAsync(10,gatherResult(1));

getRandomNumberWS(10,gatherResult(2),errorFn);

}

Intheprecedingcode,wedefinedthegatherResult()helperfunction,whichreturnsananonymousfunctionthatisusedasacallbackforourrandomnumbergenerators.ThereturnedcallbackfunctionusestheresultPosparameterastheindexofthearraywhereitwillstorethegeneratedorretrievedrandomnumber.Additionally,ittrackshowmanytimesithasbeeninvoked,asawaytoknowwhetherallthreeconcurrenttaskshaveended.Finally,rightafterthethirdandfinalinvocationofthecallback,thecallbackFnfunctionisinvokedwiththeresultsarrayasaparameter.

Anothergreatapplicationofthistechnique,otherthanAJAXcalls,istoaccessdatastoredinIndexedDB.Retrievingmanyvaluesfromthedatabaseconcurrentlycanleadtoperformancegains,sincethedataretrievalscanexecuteinparallelwithoutblockingeachother.

NoteFormoreinformationonIndexedDB,youcanvisithttps://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API/Using_IndexedDB.

Page 216: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 217: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

IntroducingtheconceptofPromisesPromises,alsoknownasFutures,aredescribedbyComputerScienceasspecializedobjectsthatareusedforsynchronizationofasynchronous,concurrent,orparallelprocedures.Theyarealsousedasproxiestopropagatetheresultofataskwhenitsgenerationcompletes.Thisway,aPromiseobjectislikeacontractwhereanoperationwilleventuallycompleteitsexecution,andanyonehavingareferencetothiscontractcandeclaretheirinteresttobenotifiedabouttheresult.

SincetheywereintroducedtoJavaScriptdevelopers,aspartofseverallibraries,theyrevolutionizedthewayweuseasynchronousfunctionsandcomposetheminimplementationwithcomplexsynchronizationschemes.Thisway,webdeveloperscancreatemoreflexible,scalable,andreadableimplementations,makingmethodinvocationswithcallbackslooklikeaprimitivepatternandeffectivelyeliminatingtheCallbackHellsituations.

OneofthekeyconceptsofPromisesisthatasynchronousmethodsreturnanobjectthatrepresentstheireventualresult.EveryPromisehasaninternalstatethatinitiallystartsasPending.Thisinternalstatecanchangeonlyonce,fromPendingtoeitherResolvedorRejected,byusingoneoftheresolve()orreject()methodsthateveryimplementationprovides.ThesemethodscanbeinvokedonlytochangethestateofaPendingPromise;inmostcases,theyareintendedtobeusedonlybytheoriginalcreatorofthePromiseobjectandnotbeavailabletoitsconsumers.Theresolve()methodcanbeinvokedwiththe

Page 218: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

resultoftheoperationasasingleparameter,whilethereject()methodisusuallyinvokedwiththeErrorthatcausedthePromiseobjecttogetRejected.

AnotherkeyconceptofPromisesistheexistenceofathen()method,givingthemthecharacterizationofthe“thenable”,asageneraltermtodescribepromisesamongallthedifferentimplementations.EveryPromiseobjectexposesathen()methodthatisusedbyacallerinordertoprovidethefunction(s)thatwillbeinvokedwhenthePromiseissettled(ResolvedorRejected).Thethen()methodcanbeinvokedwithtwofunctionsasparameters,wherethefirstisinvokedincasethePromisegetsResolved,whilethesecondisinvokedwhenitisRejected.ThefirstargumentiscommonlyreferredtoastheonFulfilled()callback,whilethesecondisreferredtoastheonRejected().

EveryPromisepreservestwointernallistcontainingalltheonFulfilled()andonRejected()callbackfunctionsthatarepassedasargumentstothethen()method.Thethen()methodcanbeinvokedseveraltimesforeachPromise,addingnewentriestotheappropriateinternallist,asfarastherespectiveparameterisactuallyafunction.WhenaPromiseeventuallygetsResolvedorRejected,ititeratesovertheappropriatelistofcallbacksandinvokestheminorder.Moreover,fromthepointthataPromisegetssettledandafter,everyfurtherusageofthethen()methodhas,asaresult,theimmediateinvocationoftheappropriateprovidedcallback.

NoteBasedonitscharacteristics,aPromisecanbelikenedtoaBrokerfromthe

Page 219: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

Publish/SubscribePatterntosomedegree.TheirkeydifferencesincludethefactsthatitcanonlybeusedforasinglePublishandthattheSubscribersgetnotifiedoftheresulteveniftheyexpressedtheirinterestafterthePublishtookplace.

Page 220: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

UsingPromisesAswesaidearlier,theconceptofPromisesrevolutionizedprogrammingofasynchronoustasksinJavaScriptand,foralongtime,theywerethenewbigthingthateveryonewasenthusiasticabout.Atthattime,manyspecializedlibrariesappearedwhereeachoneprovidedanimplementationofPromiseswithslightdifferencestoeachother.Moreover,PromiseimplementationsbecameavailableaspartofutilitylibrariessuchasjQueryandwebframeworkssuchasAngularJSandEmberJS.Atthattime,the“CommonJSPromises/A”specificationmadeitsappearanceasareferencepointandwasthefirstattempttodefinehowPromisesshouldactuallyworkacrossallimplementations.

NoteFormoreinformationonthe“CommonJSPromises/A”specification,youcanvisithttp://wiki.commonjs.org/wiki/Promises/A.

UsingthejQueryPromiseAPIAPromise-basedAPIfirstappearedinthejQuerylibraryinv1.5,basedonthe“CommonJSPromises/A”design.ThisimplementationintroducedtheadditionalconceptoftheDeferredobject,whichworkslikeaPromiseFactory.TheDeferredobjectsexposeasupersetofthemethodsthatPromisesprovide,wheretheadditionalmethodscanbeusedtodomanipulationstothestateofitsinternalPromise.Additionally,theDeferredobjectexposesapromise()methodandreturnstheactualPromiseobject,whichdoesnotexposeanywaytomanipulateitsinternalstateandjustexposesobservationmethodssuchasthen().

Inotherwords:

OnlycodethathasareferencetoaDeferredobjectcanactuallychangetheinternalstateofitsPromise,byeitherresolvingorrejectingit.AnypieceofcodethathasareferencetoaPromiseobjectcan’tchangeitsstatebutjustobserveforitsstatetochange.

NoteFormoreinformationonjQuery’sDeferredobject,youcanvisithttp://api.jquery.com/jQuery.Deferred/.

AsasimpleexampleofjQuery’sDeferredobject,let’sseehowwecanrewritethegetRandomNumberAsync()functionthatwesawearlierinthischapter,tousePromisesinsteadofCallbacks:

functiongetRandomNumberAsync(max){

vard=$.Deferred();

varrunFor=1000+Math.random()*1000;

setTimeout(function(){

varresult=Math.random()*max;

d.resolve(result);

},runFor);

returnd.promise();

Page 221: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

}

getRandomNumberAsync(10).then(function(number){

console.log(number);//returnsanumberbetween0and10

});

OurtargetistomakeanasynchronousfunctionthatreturnsaPromisethatiseventuallyresolvedtotheresultingrandomnumber.Atfirst,anewDeferredobjectiscreatedandthentherespectivePromiseobjectisreturned,byusingthepromise()methodoftheDeferred.Whentheasynchronousgenerationoftheresultiscomplete,ourmethodusestheresolve()methodoftheDeferredobjecttosetthefinalstateofthePromisethatwasreturnedearlier.

Thecallerofourfunctionusesthethen()methodofthereturnedPromise,toattachacallbackthatwillbeinvokedwiththeresultasaparameterassoonasthePromisegetsResolved.Moreover,asecondcallbackcanalsobepassedinordertogetnotifiedincasethePromisegetsRejected.Animportantthingtonoticeisthat,byfollowingtheabovepatternwherefunctionsalwaysreturnPromisesandnevertheactualDeferredobjects,wecanbesurethatonlythecreatoroftheDeferredobjectcanchangethestateofthePromise.

UsingPromises/A+Aftersometimeofhands-onexperimentationwithCommonJSPromises/A,thecommunityidentifiedsomeoftheirlimitationsandalsorecommendedsomewaystoimprovethem.TheresultwasthecreationofthePromises/A+specification,asawaytoimprovetheexistingspecificationandalsoasasecondattempttounifythevariousavailableimplementations.ThemostimportantpartsofthenewspecificationfocusedonhowchainingPromisesshouldwork,makingthemevenmoreusefulandconvenienttoworkwith.

NoteFormoreinformationonthePromises/A+specification,youcanvisithttps://promisesaplus.com/.

Finally,thePromises/A+specificationwaspublishedaspartofthe6thversionofJavaScript,commonlyreferredasES6,thatwasreleasedasastandardonJune,2015.Asaresult,Promises/A+startedtobeimplementednativelyinbrowsers,removingtheneedtousecustomthird-partylibrariesandpushingmostoftheexistinglibrariestoupgradetheirsemantics.Asofwritingofthisbook,nativePromises/A+compliantimplementationshavebeenavailableinmostmodernbrowsers,exceptforIE11,makingthemavailableout-of-the-boxtomorethan65%ofwebusers.

NoteFormoreinformationontheadoptionofA+Promisesinbrowsers,youcanvisithttp://caniuse.com/#feat=promises.

ArewriteofthegetRandomNumberAsync()functionusingthenownativelyimplementedES6A+Promiseswilllookasfollows:

Page 222: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

functiongetRandomNumberAsync(max){

returnnewPromise(function(resolve,reject){

varrunFor=1000+Math.random()*1000;

setTimeout(function(){

varresult=Math.random()*max;

resolve(result);

},runFor);

});

}

getRandomNumberAsync(10).then(function(number){

console.log(number);//returnsanumberbetween0and10

});

Asyoucansee,ES6/A+PromisesarecreatedbyusingthePromiseconstructorfunctionwiththenewkeyword.Theconstructorisinvokedwithafunctionasaparameter,whichmakesaclosurethathasaccesstoboththevariablesofthecontextthatthePromiseiscreated,butalsogetsaccesstotheresolve()andreject()functionsasparameters,whichistheonlywaytochangethestateofthenewlycreatedPromise.AfterthesetTimeout()functionfiresitscallback,theresolve()functionisinvokedwiththegeneratedrandomnumberasaparameter,changingthestateofthePromiseobjecttoFulfilled.Finally,thecallerofourfunctionusesthethen()methodofthereturnedPromiseinexactlythesamewayaswesawintheearlierimplementationthatwasusingjQuery.

ComparingjQueryandA+PromisesWewillnowhaveanin-depthstep-by-stepanalysisofthecoreconceptsofthejQueryandA+PromiseAPIs,byalsodoingaside-by-sidecodecomparisonofthetwo.Thiscanbeagreatassettohave,sinceyouwillalsobeabletouseitasareferencewhiletheimplementationsofPromisesaregraduallyadaptingtotheES6A+specification.

Theneedtounderstandfromthebeginninghowthetwovariantsdifferseemsevengreater,sincethejQueryteamhasalreadyannouncedthatVersion3.0ofthelibrarywillhavePromises/A+compliantimplementation.Specifically,asofwritingthisbook,thefirstbetaversionisalreadyout,makingthetimethatthemigrationwillhappentoappearevencloser.

NoteFormoreinformationonjQueryv3.0A+Promisesimplementation,youcanvisithttp://blog.jquery.com/2016/01/14/jquery-3-0-beta-released/.

OneofthemostobviousdifferencesbetweenthetwoimplementationsisthewaythatnewPromisesarecreated.Aswesaw,jQueryusesthe$.Deferred()functionlikeafactoryofamorecomplexobjectthatprovidesdirectaccesstothestateofthePromiseandeventuallyextractstheactualPromiseusingaseparatemethod.Ontheotherhand,A+Promisesusethenewkeywordandafunctionasaparameter,whichwillbeinvokedbytheruntimewiththeresolve()andreject()functionsasparameters:

vard=$.Deferred();

Page 223: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

setTimeout(function(){

d.resolve(7);

},2000);

varp=d.promise();//jQueryPromise

varp=newPromise(function(resolve,reject){//Promises/A+

setTimeout(function(){

resolve(7);

},2000);

});

Moreover,jQueryalsoprovidesanotherwaytocreatePromisesthatlookmorelikethewaythatA+Promiseswork.Inthiscase,$.Deferred()canbeinvokedwithafunctionasanargumentthatreceivestheDeferredobjectasaparameter:

vard=$.Deferred(function(deferred){

setTimeout(function(){

deferred.resolve(7);

},2000);

});

varp=d.promise();

Aswediscussedearlier,thesecondpossibleoutcomeofaPromiseistobeRejected,afeaturethatnicelypairswiththeclassicalexceptionsofJavaScriptinsynchronousprogramming.RejectingaPromiseiscommonlyusedforcaseswhereanerroroccursduringtheprocessingoftheresult,orinsituationswheretheresultisnotvalid.WhileES6Promisesprovideareject()functionasanargumenttothefunctionpassedtoitsconstructor,injQuery’simplementationareject()methodissimplyexposedontheDeferredobjectitself.

varp=$.Deferred(function(deferred){

deferred.reject(newError('Somethinghappened!'));

}).promise();

varp=newPromise(function(resolve,reject){

reject(newError('Somethinghappened!'));

});

Inboththeimplementations,theresultofaPromisecanberetrievedusingthethen()method,whichcanbeinvokedwithtwofunctionsasarguments,onetohandlethecasethatthePromisegetsFulfilledandoneforthecasewhereitisRejected:

p.then(function(result){//worksthesameinjQuery&ES6

console.log(result);

},function(error){

console.error('Anerroroccurred:',error);

});

BothimplementationsalsoprovideconvenientmethodstohandlethecasewherethePromisegetsRejected,butwithdifferentmethodnames.Insteadofusingp.then(null,fn),ES6Promisesprovidethecatch()methodthatnicelypairswiththetry…catchJavaScriptexpression,whilejQuery’simplementationprovides,forthesamepurpose,thefail()method:

Page 224: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

p.fail(function(error){//jQuery

console.error(error);

});

p.catch(function(error){//ES6

console.error(error);

});

Moreover,asajQueryexclusivefeature,jQueryPromisesalsoexposeadone()andanalways()method.Thecallbacksprovidedtodone()areinvokedwhenthePromisegetsFulfilledandisequivalenttousingthethen()methodwithasingleparameter,whilethecallbacksofthealways()methodareinvokedwhenthepromisegetssettledinbothpossibleoutcomes.

NoteFormoreinformationondone()andalways(),youcanvisithttp://api.jquery.com/deferred.doneandhttp://api.jquery.com/deferred.always.

Finally,bothimplementationsprovideaneasywaytodirectlycreatePromisesthatarealreadyResolvedorRejected.Thiscanbeusefulasastartingvaluetoimplementcomplexsynchronizationschemesorasaneasywaytomakesynchronousfunctionstooperatelikeasynchronousones:

varpResolved=$.Deferred().resolve(7).promise();//jQuery

varpRejected=$.Deferred().reject(newError('Something

happened!')).promise();

varpResolved=Promise.resolve(7);//ES6

varpRejected=Promise.reject(newError('Somethinghappened!'));

Page 225: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

AdvancedconceptsAnotherkeyconceptofPromisesthatmakesthemuniqueandgreatlyincreasestheirusefulnessistheabilitytoeasilycreatecompositionsofseveralPromisesthatinturnarePromisesthemselves.Compositionisavailableintwoforms,serialcompositionthatchainsPromisestogetherandparallelcompositionthatusesspecialmethodstojointheresolutionofconcurrentPromisesintoanewone.Aswesawearlierinthischapter,implementingsuchsynchronizationschemescanbehardtoimplementwiththetraditionalcallbackapproach.Promises,ontheotherhand,trytosolvethisprobleminamoreconvenientandreadableway.

Page 226: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 227: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

ChainingPromisesEveryinvocationofthethen()methodreturnsanewPromise,whosebothfinalstatusandresultdependsonthePromisethatthethen()methodwascalledon,butisalsosubjecttothevaluereturnedbytheattachedcallbacks.Thisallowsustochaincallsofthethen()method,enablingustocomposePromisesbyseriallyjoiningthem.Thisway,wecaneasilyorchestratebothasynchronousandsynchronouscode,whereeachchainingsteppropagatesitsresulttothenextoneandallowsustoconstructthefinalresultinareadableanddeclarativeway.

Let’snowproceedtoanalyzingallthedifferentwaysthatchainingofcallstothethen()methodworks.SincewewillbefocusingontheconceptsofPromisecompositionbychaining,whichworksthesameasjQueryandES6Promises,let’ssupposethatthereisapvariablethatisholdingaPromiseobjectcreatedbyeitherofthefollowinglinesofcode:

varp=$.Deferred().resolve(7).promise();

//or

varp=Promise.resolve(7);

Thesimplestusecasethatdemonstratesthepowerofchainingiswhentheinvokedcallbackreturnsa(non-promise)value.ThenewlycreatedPromiseusesthereturnedvalueasitsresult,whilepreservingthesamestateasthePromisethatthethen()methodwascalledon:

p.then(function(x){//worksthesameinjQuery&ES6

console.log(x);//logs7

returnx*3;

}).then(function(x){

console.log(x);//logs21

});

Aspecialcasetohaveinmindisthatfunctionsthatdonotreturnanythingasaresultarehandledlikereturningundefined.ThisessentiallyremovestheresultvaluefromthenewlyreturnedPromise,whichnowonlypreservestheparentsettlementstatus:

p.then(function(x){//worksthesameinjQuery&ES6

console.log(x);//logs7

}).then(function(x){

console.log(x);//logsundefined

});

InthecasewheretheinvokedcallbackreturnsanotherPromise,itsstateandresultareusedforthePromisereturnedbythethen()method:

p.then(function(x){//forjQueryPromises

console.log(x);//logs7

vard2=$.Deferred();

setTimeout(function(){

d2.resolve(x*3);

},2000);

returnd2.promise();

}).then(function(x){

Page 228: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

console.log(x);//logs21

});

p.then(function(x){//fortheA+Promises

console.log(x);//logs7

returnnewPromise(function(resolve){

setTimeout(function(){

resolve(x*3);

},2000);

});

}).then(function(x){

console.log(x);//logs21

});

TheprecedingcodesamplesdemonstratetheimplementationsforboththejQueryandA+Promises,andbothhaveequivalentresults.Inbothcases,7isloggedintotheconsolefromthefirstthen()methodinvocationandanewPromiseisthenreturnedthatwillbeResolvedatalatertimeusingsetTimeout().After2000milliseconds,thatsetTimeout()willfireitscallback,thereturnedPromisewillbeResolvedwith21asavalueand,atthatpoint,21willalsobeloggedintotheconsole.

OneextrathingtonoteisthecasewheretheoriginalPromisegetssettledandthereisnoappropriatecallbackprovidedtothechainedthen()method.Inthiscase,thenewlycreatedPromisesettlestothesamestateandresult,asthePromisewherethethen()methodwascalledon:

p.then(null,function(error){//worksthesameinjQuery&ES6

console.error('Anerrorhappened!');//doesnotrun,sincethepromise

isresolved

}).then(function(x){

console.log(x);//logs7

});

Intheprecedingexample,thecallbackwiththeconsole.errorstatementthatispassedasthesecondargumentofthethen()method,doesnotgetinvokedsincethePromiseisresolvedwith7asitsvalue.Asaresult,thecallbackofthechaineventuallyreceivesanewPromise,whichisalsoresolvedwith7asitsvalueandlogsthatintheconsole.SomethingtohaveinmindinordertodeeplyunderstandhowchainingofPromisesworks,isthatp!=p.then()inallcases.

Page 229: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

HandlingthrownerrorsThefinalconceptofchainingdefinesthecasewhereexceptionsarethrownduringtheinvocationofathen()callback.ThePromise/A+specificationdefinedthatthenewlycreatedPromiseisRejectedandthatitsresultistheErrorthatwasthrown.Moreover,theRejectionwillbubblethroughtheentirechainofPromises,enablingustobenotifiedaboutanyerrorinthechainonlydefiningtheerrorhandlingonce,neartotheendofthechain.

Unfortunately,thisisnotconsistentintheimplementationofthelateststableversionofjQuery,whichasofthewritingofthisbookisv2.2.0:

$.Deferred().resolve().promise().then(function(){

thrownewError('Somethinghappened!');

//theexecutionstopshere

}).then(null,function(x){

console.log(x);//nothinggetsprinted

});

$.Deferred().resolve().promise().then(function(){

try{//thisisaworkaround

thrownewError('Somethinghappened!');

}catch(e){

return$.Deferred().reject(e).promise();

}

}).then(function(){

console.log('Success');//notprinted

}).then(null,function(x){//almostequivalentto.fail()

console.log(x);//logs'Somethinghappened!''

});

Promise.resolve().then(function(){

thrownewError('Somethinghappened!');

}).then(function(){

console.log('Success');//notprinted

}).then(null,function(x){//equivalentto.catch()

console.log(x);//logs'Somethinghappened!''

});

Inthefirstcase,theexceptionthatisthrownstopstheexecutionofthePromisechain.Theonlywayarounditisprobablyexplicitlyaddingatry…catchstatementinsidethecallbackthatispassedtothethen()method,asshowninthesecondcasethatisdemonstrated.

Page 230: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

JoiningPromisesTheotherwayoforchestratingPromisesthatrunconcurrentlyisbycomposingthemtogether.Asanexample,let’ssupposetheexistenceoftwoPromises,p1andp2,thatgetresolvedwith7and11astheirvalues,after2000and3000milliseconds,respectively.SincethesetwoPromisesareexecutedconcurrently,thecomposedPromisewillonlyneed3000millisecondstogetResolved,asitisthegreaterofthetwodurations:

//jQuery

$.when(p1,p2).then(function(result1,result2){

console.log('p1',result1);//logs7

console.log('p2',result2);//logs11

//thiscanbeusedtomakeourcodelooklikeA+

varresults=arguments;

});

//A+

Promise.all([p1,p2]).then(function(results){

console.log('p1',results[0]);//logs7

console.log('p2',results[1]);//logs11

});

BothPromiseAPIsprovideaspecializedfunctionthatallowsustoeasilycreatePromisecompositionsandalsoretrievetheindividualresultsofthecomposition.AcomposedPromisegetsResolvedwhenallitspartsgetResolved,whileitgetsRejectedwhenanyoneofitspartsgetsRejected.Unfortunately,thetwoPromiseAPIsdiffer,notonlybythenameofthefunctions,butalsobythewaytheyareinvokedandthewaytheyprovidetheirresults.

ThejQueryimplementationprovidesthe$.when()methodthatcanbeinvokedwithanynumberofargumentsthatwewanttobecomposed.Byusingthethen()methodonacomposedjQueryPromise,wecangetnotifiedwhenthecompositiongetssettledasawholeandalsoaccesseachindividualresultasargumentsofourcallback.

Ontheotherhand,theA+PromisesspecificationprovidesusthePromise.all()methodthatisinvokedwithanarrayasitssingleparameterthatcontainsallthePromisesthatwewanttogetcomposed.ThereturnedcomposedPromisedoesnotdifferatallfromthePromisesthatwehaveseensofarandthecallbackofthethen()methodisinvokedwithanarrayasitsparameter,whichcontainsalltheresultsofthePromisesthatarepartofthecomposition.

Page 231: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

HowjQueryusesPromisesAtthetimethatjQueryaddedanimplementationofPromisestoitsAPI,italsostartedtoexposeitthroughotherasynchronousmethodsofitsAPI.Perhapsthemostwell-knownexampleofthiskindisthemethodofthe$.ajax()familythatreturnsajqXHRobject,whichisaspecializedPromiseobjectthatalsoprovidessomeextramethodsrelatedtotheAJAXrequest.

NoteFormoreinformationonthejQuery’s$.ajax()methodandthejqXHRobject,youcanvisithttp://api.jquery.com/jQuery.ajax/#jqXHR.ThejQueryteamalsodecidedtochangetheimplementationofseveralinternalpartsofthelibrarytousePromises,inordertoimprovetheirimplementations.Firstofall,the$.ready()methodisimplementedusingPromisessothattheprovidedcallbacksfireevenifthepagehasalreadybeenloadedalongtimebeforeitsinvocation.Also,someofthecomplexanimationsthatjQueryprovidesusePromisesinternallyasthepreferredwaytosynchronizetheexecutionofthesequentialpartsoftheanimationqueue.

Page 232: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

TransformingPromisestoothertypesDevelopingbyusingseveraldifferentJavaScriptlibrariesoftenmakesmanyPromiseimplementationsavailabletoourprojectsthatunfortunatelytendtohavedifferentlevelsofcompliancetothereferencePromisesspecification.ComposingPromisesreturnedbythemethodsofdifferentlibrariescanoftenleadtoproblemsthatarehardtotrackandresolve,asaresultoftheirimplementationinconsistencies.

Inordertoavoidconfusionsinsuchsituations,itisn’tconsideredagoodpracticetotransformallthePromisestoasingletypebeforeattemptingtocomposethem.ThesuggestedtypeforsuchsituationsisthePromises/A+specification,sincenotonlyisitwidelyacceptedbythecommunitybutitisalsopartofthenewlyreleasedversionofJavaScript(theES6languagespecification)thatisalreadynativelyimplementedinmanybrowsers.

TransformingtoPromises/A+Forexample,let’sseehowajQueryPromisecanbetransformedtoanA+Promisethatisavailableinmostrecentbrowsers:

varjqueryPromise=$.Deferred().resolve('IwillbeA+

compliant').promise();

varp=Promise.resolve(jqueryPromise);

p.then(function(result){

console.log(result);

});

Intheprecedingexample,thePromise.resolve()methoddetectsthatithasbeeninvokedwitha“thenable”andthatthenewlycreatedA+PromisethatisreturnedbindsitsstatusandresulttothoseoftheprovidedjQueryPromise.Thisisessentiallyequivalenttodoingsomethingasfollows:

varp=newPromise(function(resolve,reject){

jqueryPromise.then(resolve,reject);

});

Ofcourse,thisisnotlimitedtoPromisesthatarecreatedbydirectinvocationsofthe$.Deferred()method.TheabovetechniquecanalsobeusedtotransformPromisesthatarereturnedbyanyjQuerymethod.Forexample,thisishowitcanbeusedwiththe$.getJSON()method:

varaPlusAjaxPromise=Promise.resolve($.getJSON('AjaxContent.json'));

aPlusAjaxPromise.then(function(result){

console.log(result);

});

TransformingtojQueryPromisesEventhoughIwouldgenerallynotrecommendthis,itisalsopossibletotransformanyPromisetoajQueryvariant.ThenewlycreatedjQueryPromisereceivesalltheextrafunctionalitiesthatjQueryprovides,butthetransformationisnotasstraightforwardasthepreviousone:

Page 233: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

varaPromise=Promise.resolve('IwillbeajQueryPromise');

varp=$.Deferred(function(deferred){

aPromise.then(function(result){

returndeferred.resolve(result);

},function(error){

returndeferred.reject(error);

});

}).promise();

p.then(function(result){

console.log(result);

});

YoushouldonlyusetheprecedingtechniqueincaseswhereyouneedtoextendabigwebapplicationthatisalreadyimplementedusingjQueryPromises.Ontheotherhand,youshouldalsoconsiderupgradingsuchimplementations,sincethejQueryteamhasalreadyannouncedthatVersion3.0ofthelibrarywillhavePromises/A+compliantimplementation.

NoteFormoreinformationonjQueryv3.0A+Promisesimplementation,youcanvisithttp://blog.jquery.com/2016/01/14/jquery-3-0-beta-released/.

Page 234: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

SummarizingthebenefitsofPromisesOverall,thebenefitsofusingPromisesoverplainCallbacksinclude:

HavingaunifiedwaytohandletheresultofasynchronousinvocationsHavingpredictableinvocationparametersfortheusedcallbacksTheabilitytoattachmultiplehandlersforeachoutcomeofthePromiseTheguaranteethattheappropriateattachedhandlerswillexecuteevenifthePromisehasalreadybeenResolved(orRejected)Theabilitytochainasynchronousoperations,makingthemruninorderTheabilitytoeasilycreatecompositionsofasynchronousoperations,makingthemrunconcurrentlyTheconvenientwayofhandlingerrorsinPromisechains

UsingamethodthatreturnsaPromiseremovestheneedtodirectlypassfunctionsofonecontexttoanotherasaninvocationargumentandthequestionregardingwhichparametersareusedasthesuccessandtheerrorCallbacks.Moreover,wealreadyknowtosomedegreehowtoretrievetheresultofanyoperationthatreturnsaPromise,byusingthethen()method,evenbeforereadingthedocumentationaboutthemethod’sinvocationparameters.

Lessparametersoftenmeanslesscomplexity,smallerdocumentation,andlesssearchingeverytimewewanttodoamethodinvocation.Evenbetter,thereisagoodchancethattherewillonlybeasingleorafewparameters,makingtheinvocationmoresensibleandreadable.Theimplementationofasynchronousmethodsalsobecomeslesscomplex,sincethereisnolongertheneedtoacceptcallbackfunctionsasanextraargumentorhavingtoproperlyinvokethemwiththeresult.

Page 235: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 236: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

SummaryInthischapter,weanalyzedthedevelopmentpatternsthatareusedtoprogramasynchronousandconcurrentprocedures.Wealsolearnedhowtousethemtoefficientlyorchestratetheexecutionofasynchronousproceduresthatruneitherinorderorparalleltoeachother.

Atfirst,wehadarefresheronhowCallbacksareusedinJavaScriptprogrammingandhowtheyareanintegralpartofwebdevelopment.Weanalyzedtheirbenefitsandlimitationswhenusedinlargeandcompleximplementations.

Rightafterthis,wewereintroducedtotheconceptsofPromises.WelearnedhowjQuery’sDeferredandPromiseAPIsworkandhowtheydifferfromES6Promises.WealsosawwhereandhowtheyareusedinternallybyjQueryitself,asanexampleofhowtheycanleadtomorereadablecodeandsimplifysuchcompleximplementations.

Inthenextchapter,wewillproceedtolearninghowtodesign,create,anduseMockObjectsandMockServicesinourapplications.WewillanalyzethecharacteristicsthataproperMockObjectshouldhaveandunderstandhowtheycanbeusedasrepresentativeusecasesandevenastestcasesforourcode.

Page 237: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 238: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

Chapter8.MockObjectPatternInthischapterwewillshowcasetheMockObjectPattern,apatterntofacilitatethedevelopmentofapplicationswithoutactuallybeingpartofthefinalimplementation.Wewilllearnhowtodesign,createandusethisindustry-standarddesignpatterninordertocoordinateandcompletethedevelopmentofmulti-partjQueryapplicationsfaster.WewillanalyzethecharacteristicsthataproperMockObjectshouldhaveandunderstandhowtheycanbeusedasrepresentativeusecasesandevenastestcasesforourcode.

WewillseehowgoodapplicationarchitecturemakesiteasierforustouseMockObjects&Servicesbymatchingindividualpartsoftheapplication,andalsorealizethebenefitsofusingthemduringdevelopment.Bytheendofthischapter,wewillbeabletocreateMockObjects&Servicestoacceleratetheimplementationofourapplicationandalsotogetasenseoftheoverallfunctionalitylongbeforeallofitspartsarecompleted.

Inthischapter,weshall:

IntroducetheMockObjectandMockServicePatternsAnalyzethecharacteristicsthatMockObjects&ServicesshouldhaveUnderstandwhytheyfitbetterwithapplicationswithgoodarchitectureLearnhowtousetheminjQueryapplicationsasawaytodrivethedevelopmentandaccelerateit

Page 239: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

IntroducingtheMockObjectPatternThekeyconceptoftheMockObjectPatternisincreatingandusingadummyobjectthatsimulatesthebehaviorofamorecomplexobjectthatis(orwillbe)partofanimplementation.TheMockObjectshouldhavethesameAPIastheactual(orreal)object,returnsimilarresultsusingthesamedatastructures,andalsooperateinasimilarmannerwithregardstohowitsmethodsalteritsexposedstate(theproperties).

MockObjectsareusuallycreatedduringtheearlydevelopmentphasesofanapplication.TheirprimaryusecaseistoenableustoproceedwiththedevelopmentofaModule,evenifitdependsonothersthathavenotyetbeenimplemented.MockObjectscanalsobedescribedasprototypesofthedataexchangedbetweenthedifferentpartsoftheimplementation,actinglikecontractsbetweenthedevelopersandeasingtheparalleldevelopmentofinterdependentmodules.

TipInthesamewaythattheprinciplesoftheModulePatterndecoupletheimplementationsofthedifferentpartsofanapplication,creatingandusingMockObjectsandMockServicesdecouplestheirdevelopment.

CreatingMockObjectsforeveryModulebeforestartingtheirimplementationclearlydefinesthedatastructuresandAPIsthatwillbeusedbytheapplication,removinganymisconceptionsandenablingustodetectinsufficienciesintheproposedAPIs.

TipDefiningthedatastructuresthatarerequiredtodescribeaproblembeforestartingtheactualimplementationallowsustofocusontheneedsoftheapplicationandgetanideaofitsoverallcomplexityandstructure.

YoucanalwaystestanypartofyourimplementationafteranycodechangebyusingtheMockObjectsthatwerecreatedfortheoriginalimplementation.YoucanbesurethattheoriginalusecasestillworksbyusingtheMockObjectsonthemodifiedmethods.Thisisveryusefulwhenthemodifiedimplementationisapartofausecaseinvolvingseveralstages.

MockObjectsareespeciallyusefulfortracingerrorsiftheimplementationofaModulehaschangedandcausedtherestoftheapplicationtomisbehave.ByusingtheexistingMockObjects,wecaneasilyidentifytheModulethatdivergedfromtheoriginalspecification.Moreover,thesameMockObjectscanbeusedasthebasisforhighqualitytestcasessincetheyoftencontainmorerealisticsampledata,somethingespeciallyusefulifyourteamisfollowingaTestDrivenDevelopment(TDD)paradigm.

NoteInTestDrivenDevelopment(TDD),thedeveloperfirstlydefinesatestcaseforausecaseoranewfeaturethatneedstobeaddedandthenproceedswithitsimplementationbytryingtosatisfythecreatedtestcase.Formoreinformation,youcanvisit:

Page 240: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

https://www.packtpub.com/books/content/overview-tdd.

TheMockObjectPatterniscommonlyusedamongfrontendwebdeveloperstodecoupletheclient-sidedevelopmentfromthewebservicesthatthebackendwillexpose.Thathasledtowittycommentssuchas:

“Thewebservicewillalwaysbelate&changesuddenly,souseaMockinstead.”

Summarizingallofthis,themainreasonstocreateMockObjectsandServicesinclude:

Theactualobjectorserviceisnotyetimplemented.Theactualobjectisdifficulttosetupforaspecificusecase.Weneedtoemulatearareornon-deterministicbehavior.Theactualobjectbehavesinawaythatishardtoreproduce,suchasnetworkerrorsorUIevents.

Page 241: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 242: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

UsingMockObjectsinjQueryapplicationsInordertodemonstratehowtheMockObjectPatterncanbeusedduringthedevelopmentofamulti-partapplication,wewillextendthedashboardexample,aswesawinChapter4,DivideandConquerwiththeModulePattern,inordertopresentthumbnailsofYouTubevideosfromwebdevelopingconferences.Thevideoreferencesaregroupedintofourpredefinedcategoriesandtherelatedbuttonswillbedisplayedbasedonthecurrentcategoryselection,asillustratedbelow:

ThechangesthatneedtobeintroducedtotheHTMLandtheCSSareminimal.TheonlyextraCSSthatisneededfortheaboveimplementation,whencomparedtotheexistingimplementationfromChapter4,DivideandConquerwiththeModulePattern,isrelatedtothewidthofthethumbnails:

.boximg{

width:100%;

}

ThechangeintheHTMLisintendedtoorganizethe<button>elementsofeachcategory.ThischangewillmakeourimplementationmorestraightforwardsincethecategoriesandtheiritemsarenolongerstaticallydefinedintheHTMLbutareinsteadcreateddynamically,drivenbytheavailabledata.

<!--…-->

<sectionclass="dashboardCategories">

Page 243: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

<selectid="categoriesSelector"></select>

<divclass="dashboardCategoriesList"></div>

<divclass="clear"></div>

</section>

<!--…-->

IntheabovepieceofHTML,the<div>elementwiththedashboardCategoriesListCSSclass,willbeusedasacontainerforthegroupedbuttonsofthedifferentvideocategories.AftercoveringtheUIelements,let’snowmoveontotheanalysisoftheJavaScriptimplementation.

Page 244: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

DefiningtheactualservicerequirementsThevideoreferencestobedisplayedinourdashboardcouldberetrievedfromvarioussources.Forexample,youcouldmakeadirectcalltoYouTube’sclient-sideAPIoranAJAXcalltoabackendwebservice.Inalloftheabovecases,itisconsideredagoodpracticetoabstractthisdataretrievalmechanismintoaseparatemodule,followingthecodestructuringrecommendationsofthepreviouschapters.

Forthisreason,weneedtoaddanextramoduletotheexistingimplementation.Thiswillbeaservice,responsibleforprovidingthemethodsthatwillallowustoretrievethemostrelevantvideosfromeachcategoryandloadinformationforeachvideoindividually.ThiswillbeachievedbyusingthesearchVideos()andgetVideo()methodsrespectively.

Aswehavealreadysaid,oneofthemostimportantphasesofeachimplementation,especiallyincaseofparalleldevelopment,istheanalysisanddefinitionofthedatastructurestobeused.SinceourdashboardwillbeusingtheYouTubeAPI,weneedtocreatesomesampledatawhichfollowitsdatastructurerules.AfterinspectingtheAPI,weendupwithasub-setofthefieldsthatarerequiredforourdashboard,andcanproceedtocreateaJSONobjectwithmockdatatodemonstratetheuseddatastructure:

{

"items":[{

"id":{"videoId":"UdQbBq3APAQ"},

"snippet":{

"title":"jQueryUIDevelopmentTutorial:jQueryUITooltip|

packtpub.com",

"thumbnails":{

"default":{"url":

"https://i.ytimg.com/vi/UdQbBq3APAQ/default.jpg"},

"medium":{"url":

"https://i.ytimg.com/vi/UdQbBq3APAQ/mqdefault.jpg"},

"high":{"url":"https://i.ytimg.com/vi/UdQbBq3APAQ/hqdefault.jpg"

}

}

}

}/*,...*/]

}

NoteFormoreinformationabouttheYouTubeAPI,youcanvisit:https://developers.google.com/youtube/v3/getting-started.

Ourserviceprovidestwocoremethods,oneforsearchingforvideosinaspecifiedcategoryandoneforretrievinginformationaboutaspecificvideo.Thestructureofthesampleobjectisusedforthesearchmethodtoretrieveasetofrelevantitems,whilethemethodforretrievinginformationforasinglevideousesthedatastructureofeachindividualitem.TheresultingimplementationforthevideoinformationretrievalisinaseparatemodulenamedvideoService,whichwillbeavailableonthedashboard.videoServicenamespace,andourHTMLwouldcontaina<script>referencelikethefollowing:

Page 245: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

<scripttype="text/javascript"src="dashboard.videoservice.js"></script>

Page 246: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

ImplementingaMockServiceChangingthe<script>referencesoftheserviceimplementationwiththeMockServiceandviceversashouldleaveuswithaworkingapplication,helpingusprogressandtesttherestoftheimplementationbeforetheactualimplementationofthevideoserviceisfinished.Asaresult,theMockServiceneedstousethesamedashboard.videoServicenamespace,butitsimplementationshouldbeinadifferentlynamedfilesuchasdashboard.videoservicemock.jsthatsimplyaddsthe“mock”suffix.

Aswehavealreadymentioned,itisagoodpracticetoplaceallourmockdataunderasinglevariable.Moreover,iftherearealotofMockedObjects,itiscommontoplacetheminadifferentfilealtogether,withanestednamespace.Inourcase,thefilewiththemockdataisnameddashboard.videoservicemock.mockdata.jsanditsnamespaceisdashboard.videoService.mockData,whileexposingthesearchesandvideospropertiesthatwillbeusedbythetwocoremethodsofourMockService.

EventhoughtheimplementationsofMockServicesshouldbesimple,theyhavetheirowncomplexitysincetheyneedtoprovidethesamemethodsasthetargetimplementations,acceptthesamearguments,andlookasiftheyareoperatingintheexactsameway.Forexample,inourcase,thevideoretrievalserviceneedstobeasynchronousanditsimplementationneedstoreturnPromises:

(function(){//dashboard.videoservicemock.js

'usestrict';

dashboard.videoService=dashboard.videoService||{};

dashboard.videoService.searchVideos=function(searchKeywords){

return$.Deferred(function(deferred){

varsearches=dashboard.videoService.mockData.searches;

for(vari=0;i<searches.length;i++){

if(searches[i].keywords===searchKeywords){

//returnthefirstmatchingsearchresults

deferred.resolve(searches[i].data);

return;

}

}

deferred.reject('Notfound!');

}).promise();

};

dashboard.videoService.getVideo=function(videoTitle){

return$.Deferred(function(deferred){

varvideos=dashboard.videoService.mockData.allVideos;

for(vari=0;i<videos.length;i++){

if(videos[i].snippet.title===videoTitle){

//returnthefirstmatchingitem

deferred.resolve(videos[i]);

return;

}

}

deferred.reject('Notfound!');

Page 247: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

}).promise();

};

varvideoBaseUrl='https://www.youtube.com/watch?v=';

dashboard.videoService.getVideoUrl=function(videoId){

returnvideoBaseUrl+videoId;

};

})();

AsshownintheMockServiceimplementationabove,thesearchVideos()andgetVideo()methods,areiteratingoverthearrayswiththemockdataandreturnaPromisethatiseitherResolvedwithanappropriateMockObjectorRejectedwhensuchanobjectisnotfound.Finally,youcanseebelowthecodeforthesub-modulecontainingtheMockObjects,followingthedatastructurethatwedescribedearlier.NotethatwestoretheMockObjectsofallcategoriesintheallVideospropertyinordertomakesearchingwiththemockgetVideo()methodsimpler.

(function(){//dashboard.videoservicemock.mockdata.js

'usestrict';

dashboard.videoService.mockData=dashboard.videoService.mockData||

{};

dashboard.videoService.mockData.searches=[{

keywords:'jQueryconference',

data:{

"items":[/*...*/]

}

}/*,...*/];

varallVideos=[];

varsearches=dashboard.videoService.mockData.searches;

for(vari=0;i<searches.length;i++){

allVideos=allVideos.concat(searches[i].data.items);

}

dashboard.videoService.mockData.allVideos=allVideos;

})();

ExperimentingwiththeimplementationofsomeMockServiceswillgetyoufamiliarwiththeircommonimplementationpatternsinaveryshortperiodoftime.Beyondthat,youwillbeabletoeasilycreateMockObjectsandServices,helpingyoudesigntheAPIsofyourapplications,trythemoutbyusingthemocksandfinallysettleonthebestmatchingmethodsanddatastructuresforeachusecase.

TipUsingthejQueryMockjaxlibrary

TheMockjaxjQueryPluginlibrary(availableathttps://github.com/jakerella/jquery-mockjax)focusesonprovidingasimplewayofmockingorsimulatingAJAXrequestsandresponses.ThisreducesthecodeneededtofullyimplementyourownMockServices,ifallthatyouneedistointerceptanAJAXrequesttoawebserviceandreturnaMock

Page 248: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

Objectinstead.

Page 249: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

UsingtheMockServiceInordertoaddthefunctionalitythatwedescribedearliertotheexistingdashboardimplementation,weneedtointroducesomechangestothecategoriesandtheinformationBoxmodules,addingthecodethatwillconsumethemethodsofourservice.AsarepresentativeexampleofusingthenewlycreatedMockService,let’stakealookattheimplementationoftheopenNew()method,intheinformationBoxmodule:

dashboard.informationBox.openNew=function(itemName){

var$box=$('<divclass="boxsizer"><articleclass="box">'+

'<headerclass="boxHeader">'+

'<buttonclass="boxCloseButton">&#10006;</button>'+

itemName+

'</header>'+

'<divclass="boxContent">Loading…</div>'+

'</article></div>');

$boxContainer.append($box);

dashboard.videoService.getVideo(itemName).then(function(result){

var$a=$('<a>').attr('href',

dashboard.videoService.getVideoUrl(result.id.videoId));

$a.append($('<img/>').attr('src',

result.snippet.thumbnails.medium.url));

$box.find('.boxContent').empty().append($a);

}).fail(function(){

$buttonContainer.html('Anerroroccurred!');

});

};

ThismethodinitiallyopensanewinformationboxwithaLoading…labelasitscontentandusesthedashboard.videoService.getVideo()methodtoretrievethedetailsoftherequestedvideoasynchronously.Finally,whenthereturnedPromisegetsresolved,itreplacestheLoading…labelwithananchorcontainingthethumbnailofthevideo.

Page 250: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 251: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

SummaryInthischapter,welearnedhowtodesign,createanduseMockObjectsandMockServicesinourapplications.WeanalyzedthecharacteristicsthatMockObjectsshouldhaveandunderstoodhowtheycanbeusedasrepresentativeusecases.WearenowabletouseMockObjects&Servicestoacceleratetheimplementationofourapplicationsandgetabettersenseofitsoverallfunctionality,longbeforeallofitsindividualpartsarecompleted.

Inthenextchapter,wewillbeintroducedtoclient-sidetemplatingandlearnhowtogeneratecomplexHTMLstructuresinthebrowserfromreadabletemplatesefficiently.WewillgetanintroductiontoUnderscore.jsandHandlebars.js,analyzetheirconventions,evaluatetheirfeaturesandfindwhichonebettersuitsourtaste.

Page 252: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 253: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

Chapter9.Client-sideTemplatingThischapterwilldemonstratesomeofthemostwidelyusedlibrariestocreatecomplexHTMLtemplatesfaster,whilemakingourimplementationeasiertoreadandunderstandwhencomparedtotraditionalstringconcatenationtechniques.WewilllearninmoredetailhowtousetheUnderscore.jsandHandlebars.jstemplatinglibraries,getatasteoftheirconventions,evaluatetheirfeaturesandfindtheonethatbestsuitsourtaste.

Bytheendofthischapter,wewillbeabletogeneratecomplexHTMLstructuresinthebrowserefficientlybyusingreadabletemplatesandutilizingtheuniquecharacteristicsofeachtemplatinglibrary.

Inthischapter,wewill:

DiscussthebenefitsofusingaspecializedtemplatinglibraryIntroducethecurrenttrendsinclient-sidetemplating,specificallythetoprepresentativeofthefamiliesthatuse<%%>and{{}}astheirplaceholdersIntroduceUnderscore.jsasanexampleofthefamilyoftemplatingenginesthatuse<%%>placeholdersIntroduceHandlebars.jsasanexampleofthefamilyoftemplatingenginesthatusecurlybraces{{}}placeholders

Page 254: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

IntroducingUnderscore.jsUnderscore.jsisaJavaScriptlibrarythatprovidesacollectionofutilitymethodsthathelpwebdevelopersworkmoreefficientlyandfocusontheactualimplementationoftheirapplicationratherthanbotheringwithrepetitivealgorithmicproblems.Underscore.jsis,bydefault,accessiblethroughthe“_”identifieroftheglobalnamespaceandthat’sexactlywhereitsnamecomesfrom.

NoteAswiththe$identifierinjQuery,theunderscore“_”identifiercanalsobeusedasavariablenameinJavaScript.

Oneoftheutilityfunctionsthatitprovidesisthe_.template()method,whichprovidesuswithaconvenientwayofinterpolatingspecificvaluesintoexistingtemplatestringsthatfollowaspecificformat.The_.template()methodrecognizesthreespecialplaceholdernotationsinsidetemplates,whichareusedtoadddynamiccharacteristics:

The<%=%>notationisusedasthesimplestwaytointerpolateavalueofavariableoranexpressioninatemplate.The<%-%>notationperformsHTMLescapingonavariableorexpressionandtheninterpolatesitinatemplate.The<%%>notationisusedtoexecuteanyvalidJavaScriptstatementaspartofthetemplategeneration.

The_.template()methodacceptsatemplatestringthatfollowsthesecharacteristicsandreturnsaplainJavaScriptfunction,commonlyreferredtoasthetemplatefunction,whichcanbeinvokedwithanobjectcontainingthevaluesthataregoingtobeinterpolatedinthetemplate.Theresultoftheinvocationofthetemplatefunctionisastringvalue,whichistheresultoftheinterpolationoftheprovidedvaluesinsidethetemplate:

vartemplateFn=_.template('<h1><%=title%></h1>');

varresultHtml=templateFn({

title:'Underscore.jsexample'

});

Asanexample,theabovecodereturns<h1>Underscore.jsexample</h1>andisequivalenttothefollowingshorthandinvocation:

varresultHtml=_.template('<h1><%=title%></h1>')({

title:'Underscore.jsexample'

});

NoteFormoreinformationaboutthe_.templatemethod,youcanreadthedocumentationat:http://underscorejs.org/#template.

WhatmakesUnderscore.jstemplatesveryflexibleisthe<%%>notation,whichallowsustoperformanymethodinvocationandis,forexample,usedastherecommendedwaytocreateloopsinatemplate.Ontheotherhand,overusingthisfeaturemayaddtoomuch

Page 255: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

logictoyourtemplates,whichisaknownanti-patternfoundinmanyotherframeworks,violatingtheprincipleofSeparationofConcerns.

Page 256: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

UsingUnderscore.jstemplatesinourapplicationsAsanexampleofusingUnderscore.jsfortemplating,wewillnowuseittorefactortheHTMLcodegenerationwhichtakesplaceinsomemodulesofthedashboardexample,aswesawinpreviouschapters.ThemodificationsrequiredtotheexistingimplementationarelimitedtothecategoriesandtheinformationBoxmodules,whichmanipulatetheDOMtreeofthepagebyaddingnewelements.

Thefirstplacethatsucharefactorcanbeappliedisintheinit()methodofthecategoriesmodule.Wecanmodifythecodethatcreatestheavailable<option>softhe<select>categorytolooklikethis:

varoptionTemplate=_.template('<optionvalue="<%=value%>"><%-title%>

</option>');

varoptionsHtmlArray=[];

for(vari=0;i<dashboard.categories.data.length;i++){

varcategoryInfo=dashboard.categories.data[i];

optionsHtmlArray.push(optionTemplate({

value:i,

title:categoryInfo.title

}));

}

$categoriesSelector.append(optionsHtmlArray.join(''));

Asyoucansee,weiterateoverthecategoriesofthedashboardinordertocreateandappendtheappropriate<option>elementstothe<select>categoryelement.Inourtemplate,weareusingthe<%=%>notationforthevalueattributeofthe<option>sinceweknowthatitwillholdanintegervaluethatdoesnotneedescaping.Ontheotherhand,weareusingthe<%-%>notationforthecontentpartofeach<option>inordertoescapethetitleofeachcategoryforthecaseitsvalueisnotanHTML-safestring.

Weareusingthe_.template()methodoutsidetheforloopinordertocreateasinglecompiledtemplatefunctionthatwillbereusedoneachiterationoftheforloop.Inthisway,thebrowsernotonlyexecutesthe_.template()methodjustonce,butalsooptimizesthegeneratedtemplatefunctionandmakesitrunfasteroneachsubsequentexecutioninsidetheforloop.Lastly,weareusingthejoin('')methodtocombinealltheHTMLstringsoftheoptionsHtmlArrayvariableandappend()theresulttotheDOMwithasingleoperation.

Analternativeandpossiblysimplerwaytoachievethesameresultisbycombiningthe<%%>notationandthe_.each()methodthatUnderscore.jsprovides,enablingustoimplementaloopinsidethetemplateitself.Inthisway,thetemplatewillberesponsiblefortheiterationovertheprovidedarrayofcategories,movingthecomplexityfromtheimplementationofthemoduleintothetemplate.

vartemplateSource=''.concat(

'<%_.each(categoryInfos,function(categoryInfo,i){%>',

'<optionvalue="<%=i%>"><%-categoryInfo.title%></option>',

'<%});%>');

varoptionsHtml=_.template(templateSource)({

categoryInfos:dashboard.categories.data

Page 257: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

});

$categoriesSelector.append(optionsHtml);

Asyoucanseeintheabovecode,ourJavaScriptimplementationnolongercontainsaforloop,reducingitscomplexityandtherequirednesting.Thereisonlyasinglecalltothe_.template()method,whichnicelyabstractstheimplementationtoanoperationthatgeneratestheHTMLandrendersthe<option>elementsforallthecategories.YoucanalsoseehownicelythistechniquefitsinwiththeCompositelogicthatjQueryitselffollows,inwhichthemethodsaredesignedtooperateovercollectionsofelementsinsteadofsingleitems.

SeparatingHTMLtemplatesfromJavaScriptcodeEvenafterintroducingalloftheaboveimprovements,itsoonstartstobecomeobviousthatwritingtemplatesinbetweenyourapplicationlogicmightnotbethebestapproachtofollow.Assoonasyourapplicationbecomescomplexenough,orwhenyouneedtousetemplatesthataremorethanafewlineslong,theimplementationstartstofeelfragmentedbythemixoftheapplication’slogicandtheHTMLtemplates.

AcleanerapproachtothisproblemistostoreyourtemplatesalongsidetherestoftheHTMLcodeofyourpage.ThisisagoodsteptowardsbetterSeparationofConcernssinceitproperlyisolatesthepresentationfromtheapplicationlogic.

InordertoincludeHTMLtemplatesaspartofwebpagesinaninactiveform,weneedtouseahosttagthatwillpreventthemfrombeingrendered,butalsoallowustoretrieveitscontentprogrammaticallywhenneeded.Forthispurpose,wecanuse<script>tagsinsidethe<head>orthe<body>ofourpageandspecifyanytypeotherthanthecommontext/javascriptthatwenormallyuseforourJavaScriptcode.Theoperationprinciplebehindthisisthatbrowsersdonottrytoparse,executeorrenderthecontentof<script>tags,incasetheirtypeattributeisn’trecognized.Aftersomeexperimentation,thecommunityofUnderscore.jsusershaslargelyadoptedthispracticeandagreedtospecifytext/templateasthepreferredtypeforthese<script>tags,inanattempttomaketheseimplementationsmoreuniformamongdevelopers.

TipEventhoughUnderscore.jsisneitheropinionatednorcontainsanyimplementationspecifictothewaythatthetemplatesbecomeavailable,usingtext/template<script>tagsand/orAJAXrequestshavebeenvaluabletechniquesthatarewidelyusedandareconsideredbestpractices.

Asanexampleofacomplextemplatethatwouldbebeneficialtomoveintoa<script>tag,wewillrefactortotheopenNew()methodoftheinformationBoxmodule.Asyoucanseeinthecodebelow,theresulting<script>tagiscleanlyformattedandwenolongerneedtousestringconcatenationforthedefinitionofthemulti-linetemplate:

<scriptid="box-template"type="text/template">

<divclass="boxsizer">

<articleclass="box">

<headerclass="boxHeader">

Page 258: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

<buttonclass="boxCloseButton">&#10006;</button>

<%-itemName%>

</header>

<divclass="boxContent">Loading…</div>

</article>

</div>

</script>

AgoodpracticewhenmovingHTMLtemplatesoutofourcodeistowriteanabstractedmechanismtoberesponsibleforretrievingthemandprovidingthecompiledtemplatefunction.Thisapproachnotonlydecouplestherestoftheimplementationfromthetemplateretrievalmechanismbutalsomakesitlessrepetitiveandcreatesacentralizedmethoddesignedtoprovidetemplatesfortherestoftheapplication.Moreover,aswecanseebelow,thisapproachalsoallowsustooptimizethewaythattemplatesareretrieved,propagatingthebenefitstoalltheplacesthattheyareused.

vartemplateCache={};

functiongetEmbeddedTemplate(templateName){

varcompiledTemplate=templateCache[templateName];

if(!compiledTemplate){

vartemplate=$('#'+templateName).html();

compiledTemplate=_.template(template);

templateCache[templateName]=compiledTemplate;

}

returncompiledTemplate;

}

dashboard.informationBox.openNew=function(itemName){

varboxCompiledTemplate=getEmbeddedTemplate('box-template');

varboxHtml=boxCompiledTemplate({

itemName:itemName

});

var$box=$(boxHtml).appendTo($boxContainer);

/*...*/

};

Asshownintheaboveimplementation,theopenNew()methodoftheinformationBoxmodulesimplyinvokesthegetEmbeddedTemplate()functionbypassingauniqueidentifierthatisassociatedwiththerequestedtemplateandusesthereturnedtemplatefunctiontogeneratethenewbox’sHTMLandfinallyappendittothepage.ThemostinterestingpartoftheimplementationisthegetEmbeddedTemplate()method,whichusesthetemplateCachevariableasadictionarytoholdallthepreviouslycompiledtemplatefunctions.

Thefirststepisalwaystocheckwhethertherequestedtemplateidentifierexistsinourtemplatecache.Ifnot,thentheDOMtreeofthepageissearchedforthe<script>tagwiththerelatedIDanditsHTMLcontentisusedtocreatethetemplatefunction,whichisthenstoredinthecacheandreturnedtothecaller.

KeepinmindthatitisagoodpracticetouseaspecificprefixorsuffixforalltheidentifiersofyourHTMLtemplatesinordertoavoidconflictswiththeIDsofotherpage

Page 259: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

elements.Forthispurpose,intheaboveexampleweusedthe-templateasasuffixoftheidentifierofourboxtemplate.

Ideally,theimplementationofthetemplateprovidermethodshouldbeinaseparatemodulethatwillbeusedbyallthepartsofanapplicationbut,sinceinourdashboardthisisusedinonlyoneplace,wemettheneedsofourdemonstrationbysimplyusingafunction.

Page 260: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 261: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

IntroducingHandlebars.jsHandlebars.js,orsimplyHandlebars,isaspecializedclient-sidetemplatinglibrarythatenableswebdeveloperstocreatesemantictemplateseffectively.UsingHandlebarsfortemplatingleadstothecreationoflogic-freetemplateswhichensuresthattheviewandthecodeareisolated,helpingpreservetheSeparationofConcernsprinciple.ItislargelycompatiblewithMustachetemplates,whichareatemplatinglanguagespecificationthathaveproventheireffectivenessovertimeandhavemanyimplementationsforallthemajorprogramminglanguages.Additionally,HandlebarsprovidesasetofextensionsontopoftheMustachetemplatespecification,suchashelpermethodsandpartials,asameansofextendingthetemplatingengineandcreatingmoreeffectivetemplates.

NoteYoucanseeallthedocumentationforHandlebarsat:http://handlebarsjs.com/.YoucangetmoreinformationaboutMustacheinJavaScriptat:https://github.com/janl/mustache.js/.

ThemaintemplatenotationthatHandlebarsprovidesisthedoublecurlybracessyntax{{}}.AsHandlebarswasdesignedtobeusedforHTMLtemplatesfromthebeginning,thisnotationalsoappliesHTMLescapingbydefault,loweringthechancesthatanon-escapedvaluecouldreachthetemplatecausingpotentialsecurityproblems.Ifanon-escapedinterpolationisrequiredforaspecificpartofatemplate,wecanusethetriplecurlybracesnotation{{{}}}.

Moreover,sinceHandlebarspreventsusfrominvokingmethodsdirectlyfromwithinatemplate,itprovidesuswiththeabilitytodefineandusehelpermethodsandblockexpressionsasawaytocovermorecomplexusecaseswhilealsohelpingtomaintainourtemplatesascleanandreadableaspossible.Thesetofbuilt-inhelpersincludesthe{{#if}}and{{#each}}helperswhichallowustoperformiterationsoverarraysandchangetheoutcomesofatemplatebasedonconditionsveryeasily.

ThecentralmethodoftheHandlebarslibraryistheHandlebars.compile()method,whichacceptsatemplatestringasaparameterandreturnsafunctionthatcanbeusedtogeneratestringvaluesthatfollowtheformoftheprovidedtemplate.Thisfunctioncanthenbeinvoked(asinUnderscore.js)withanobjectasaparameter,thepropertiesofwhichwillbeusedasacontextfortheevaluationofalltheHandlebarsexpressions(thecurlybracesnotations)thatweredefinedintheoriginaltemplate:

vartemplateFn=Handlebars.compile('<h1>!!!{{title}}!!!</h1>');

varresultHtml=templateFn({

title:'>Handlebarsexample<'

});

Asanexample,theabovecodereturns"<h1>!!!&gt;Handlebarsexample&lt;!!!</h1>",turningtheinterpolatedtitleintoasafeHTMLstring,butonewhichwouldotherwiserenderproperlywhenattachedtotheDOMtreeofapage.Ofcourse,thesameresultcanbeachievedwiththefollowingshorthandinvocation,ifwedon’tneedtokeepareferencetothecompiledtemplatefunctionforfutureuse:

Page 262: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

varresultHtml=Handlebars.compile('<h1>!!!{{title}}!!!</h1>')({

title:'>Handlebarsexample<'

});

Page 263: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

UsingHandlebars.jsinourapplicationsAsanexampleofusingHandlebars.jsfortemplatingandinordertodemonstrateitsdifferencesfromUnderscore.jstemplates,wewillnowuseittorefactorourdashboardexample,likewedidintheprevioussection.Likebefore,therefactoringislimitedtothecategoriesandtheinformationBoxmodules,whichmanipulatetheDOMtreeofthepagebyaddingnewelements.

Therefactoredimplementationoftheinit()methodofthecategoriesmoduleshouldlooklikethis:

varoptionTemplate=Handlebars.compile('<optionvalue="{{value}}">{{

title}}</option>');

varoptionsHtmlArray=[];

for(vari=0;i<dashboard.categories.data.length;i++){

varcategoryInfo=dashboard.categories.data[i];

optionsHtmlArray.push(optionTemplate({

value:i,

title:categoryInfo.title

}));

}

$categoriesSelector.append(optionsHtmlArray.join(''));

Firstofall,wehaveusedtheHandlebars.compile()methodwhichgeneratesandreturnsatemplatefunctionbasedontheprovidedtemplatestring.ThemaindifferencewiththeUnderscore.jsimplementationwesawintheprevioussection,isthatwenowusethedoublecurlybracesnotation{{}}tointerpolatevaluesinourtemplate.Apartfromthedifferentappearance,Handlebars.jsalsodoesHTMLstringescapingbydefaultinanattempttoeliminateHTMLinjectionsecurityholesbymakingescapingpartofitsprimaryusecase.

Aswedidearlierinthischapter,wewillcreatethetemplatefunctionoutsidetheforloopanduseittogeneratetheHTMLforeach<option>element.AllthegeneratedHTMLstringsaregatheredinanarrayandarefinallycombinedandattachedtotheDOMtreewithasingleoperation,usingthe$.append()method.

ThenextincrementalsteptoreducethecomplexityofourimplementationistoabstracttheiterationsawayfromourJavaScriptcodeusingtheloopingcapabilitiesofthetemplatingengineitself:

vartemplateSource=''.concat(

'{{#eachcategoryInfos}}',

'<optionvalue="{{@index}}">{{title}}</option>',

'{{/each}}');

varoptionsHtml=Handlebars.compile(templateSource)({

categoryInfos:dashboard.categories.data

});

$categoriesSelector.append(optionsHtml);

TheHandlebars.jslibraryallowsustoachievethatbyusingthespecial{{#each}}notation.Inbetweenthe{{#each}}and{{/each}},thecontextofthetemplateischangedtomatcheachindividualobjectoftheiteration,allowingtodirectlyaccessand

Page 264: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

interpolatethe{{title}}ofeachobjectinthecategoryInfosarray.Moreover,inordertoaccesstheloopcounter,Handlebarsprovidesuswiththespecial@indexvariableaspartofthecontextoftheloop.

NoteForafulllistofallthespecialnotationsthatHandlebarsprovides,youcanreadthedocumentationat:http://handlebarsjs.com/reference.html

SeparatingHTMLtemplatesfromJavaScriptcodeLikemosttemplatingengines,HandlebarsalsoleadsustoisolateourtemplatesfromtheJavaScriptimplementationofourapplicationanddeliverthemtothebrowserbyincludingthemin<script>tags,insidetheHTMLofourpages.Moreover,Handlebarsisopinionatedandprefersthespecialtext/x-handlebars-templateasthetypeattributeforall<script>tagsthatcontainHandlebarstemplates.Forexample,hereishowthetemplateforthedashboard’sboxesshouldbedefinedaccordingtothelibraryrecommendations:

<scriptid="box-template"type="text/x-handlebars-template">

<divclass="boxsizer">

<articleclass="box">

<headerclass="boxHeader">

<buttonclass="boxCloseButton">&#10006;</button>

{{itemName}}

</header>

<divclass="boxContent">Loading…</div>

</article>

</div>

</script>

TipEventhoughourimplementationwouldstillworkifadifferenttypewasspecifiedforthe<script>tag,followingthelibrary’sguidelinescanobviouslymakeimplementationsmoreuniformamongdevelopers.

Aswedidearlierinthischapter,wewillfollowthebestpracticeofcreatingaseparatefunctiontoberesponsibleforprovidingthetemplateswherevertheyareneededintheapplication:

vartemplateCache={};

functiongetEmbeddedTemplate(templateName){

varcompiledTemplate=templateCache[templateName];

if(!compiledTemplate){

vartemplate=$('#'+templateName).html();

compiledTemplate=Handlebars.compile(template);

templateCache[templateName]=compiledTemplate;

}

returncompiledTemplate;

}

dashboard.informationBox.openNew=function(itemName){

Page 265: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

varboxCompiledTemplate=getEmbeddedTemplate('box-template');

varboxHtml=boxCompiledTemplate({

itemName:itemName

});

var$box=$(boxHtml).appendTo($boxContainer);

/*...*/

};

Asyoucansee,theimplementationismostlythesameastheUndescore.jsexamplethatwesawearlierinthischapter.TheonlydifferenceisthatwearenowusingtheHandlebars.compile()methodtogeneratethecompiledtemplatefunctionsfromtheretrievedtemplates.

Pre-compilingtemplatesAnextrafeatureoftheHandlebarslibraryisthesupportfortemplatepre-compilation.Thisallowsustopre-generateallthetemplatefunctionswithasimpleterminalcommandandthenhaveourserverdelivertothemtothebrowser,insteadoftheactualtemplates.Inthisway,thebrowserwillbeabletousethepre-compiledtemplatesdirectly,removingtheneedforthecompilationofeachindividualtemplateandmakingtheexecutionofthelibraryandourapplicationfaster.

Inordertopre-compileourtemplates,wefirstneedtoplacetheminseparatefiles.TheHandlebarsdocumentationsuggestsusingthe.handlebarsextensionforourfilesbutwecanstillusethe.htmlextensionifitispreferred.Afterinstallingthecompilationtoolonourdevelopmentmachine(withnpminstallhandlebars-g),wecanissuethefollowingcommandinourterminaltocompileatemplate:

handlebarsbox-template.handlebars-fbox-template.js

Thiswillgeneratethebox-template.jsfilethatisactuallyamini-moduledefinitionthataddsthetemplatetoHandlebars.templates.ThegeneratedfilecanthenbecombinedandminifiedlikeregularJavaScriptfilesand,whenloadedbyabrowser,thetemplatefunctionwillbecomeavailablethroughtheHandlebars.templates['box-template']property.

NoteKeepinmindthatifthe.htmlextensionisbeingusedforthetemplates,thenthepre-compiledtemplatefunctionwillbeavailablethroughtheHandlebars.templates['box-template.html']property.

Asyoucansee,usingatemplateproviderfunctionassistswiththemigrationofanexistingapplicationtopre-compiledtemplatessinceitallowsustoencapsulatethewaythatthetemplatesareretrieved.Movingtopre-compiledtemplatesonlyrequireschangingthegetEmbeddedTemplate()tosomethinglikethis:

functiongetEmbeddedTemplate(templateName){

returnHandlebars.templates[templateName];

}

Note

Page 266: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

Formoreinformationabouttemplatepre-compilationinHandlebars,readthedocumentationat:http://handlebarsjs.com/precompilation.html.

Page 267: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 268: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

RetrievingHTMLtemplatesasynchronouslyThefinalsteptomasteringclient-sidetemplatingisadevelopmentpracticethatallowsustoloadtemplatesdynamicallyandusetheminawebpagethathasalreadybeenloaded.Thisapproachcanleadtomorescalableimplementationsthantheapproachofembeddingalltheavailabletemplatesas<script>tagsinsidetheHTMLsourceofeachpage.

Thekeyelementofthistechniqueistoloadeachtemplateonlywhenitisrequiredforthepresentationofawebpage,commonlyafterauseraction.Themainbenefitsofthisapproacharethat:

TheinitialpageloadtimeisreducedsincetheHTMLofthepageissmaller.Thegainsfromthereductionofthepagesizebecomeevengreaterifourapplicationhasalotoftemplatesthatareusedonlyundercertaincircumstances,forexample,afterspecificuserinteractions.Theuseronlydownloadsatemplateifitisactuallygoingtobeused.Inthisway,thesizeofthetotaldownloadedresourcesforeachpageloadcanbereduced.Subsequentrequestsforanalreadyloadedtemplatewillnotleadtoanextradownload,sincethebrowser’sHTTPcachingmechanismwillreturnthecachedresource.Additionally,sincethebrowsercacheisusedforallHTTPrequestsregardlessofthepagefromwhichtheyoriginate,usersonlyhavetodownloadtherequiredtemplateoncewhileusingourwebapplication.

Becauseofitsbenefitstouserexperienceanditsscalability,thistechniqueiswidelyusedbythemostpopularwebmailandsocialnetworkingwebsites,wherevariousHTMLtemplatesandJavaScriptmodulesareloadeddynamically,basedonuseractions.

NoteFormoreinformationonhowjQuerycanbeusedtoloadJavaScriptmodulesonapagedynamically,readthedocumentationforthe$.getScript()methodat:https://api.jquery.com/jQuery.getScript/.

Page 269: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

AdoptingitinanexistingimplementationToillustratethistechnique,wewillchangetheUnderscore.jsandHandlebars.jsimplementationsoftheinformationBoxmodulesothatitfetchestheboxtemplateforourdashboardusinganAJAXrequest.

Let’sproceedbyanalyzingthenecessarychangesforourUnderscore.jsimplementation:

vartemplateCache={};

functiongetAjaxTemplate(templateName){

varcompiledTemplate=templateCache[templateName];

if(compiledTemplate){

return$.Deferred().resolve(compiledTemplate);

}

return$.ajax({

mimeType:'text/html',

url:templateName+'.html'

}).then(function(template){

templateCache[templateName]=_.template(template);

returntemplateCache[templateName];

});

}

Asyoucanseeintheabovecode,wehaveimplementedthegetAjaxTemplate()functionasawayofdecouplingthemechanismthatisresponsibleforfetchingthetemplatefromtheimplementationthatusesit.ThisimplementationhasalotincommonwiththegetEmbeddedTemplate()functionthatweusedearlier,themaindifferencebeingthatthegetAjaxTemplate()functionisasynchronousand,asaresult,returnsaPromise.

ThegetAjaxTemplate()functionfirstlycheckswhetherornottherequestedtemplatealreadyexistsinitscache,asanextraattempttoreduceHTTPrequeststotheserver.Ifthetemplateisfoundinthecache,thenitisreturnedaspartofaResolvedPromise,otherwiseweinitiateanAJAXrequestusingthe$.ajax()methodtoretrieveitfromtheserver.Likebefore,weneedtohaveaconventionregardingthenamingofthetemplateHTMLfilesandthepathusedtostorethemintheserver.Inourexample,wearelookinginthesamedirectoryasthewebpageitselfandjustappendingthe.htmlfileextension.Anextraconcerninsomecases,dependingonthewebserverused,isthedefinitionofthemimeTypeoftheresourceastext/html.

WhentheAJAXrequestcompletes,thethen()methodisexecutedwiththecontentofthetemplateasastringparameter,whichisusedtogeneratethecompiledtemplatefunction.OurimplementationfinallyreturnsthecompiledtemplatefunctionastheresultofthechainedPromise,rightafteraddingittoitscache.SincethegetAjaxTemplate()functionisasynchronous,wealsohadtochangetheimplementationoftheopenNew()methodandmoveallthecodeusingthereturnedtemplatefunctioninsideathen()callback.Apartfromthis,theimplementationhasremainedthesameandusesthetemplatefunctioninexactlythesamewayasbefore.

dashboard.informationBox.openNew=function(itemName){

vartemplatePromise=getAjaxTemplate('box-template');

Page 270: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

templatePromise.then(function(boxCompiledTemplate){

varboxHtml=boxCompiledTemplate({

itemName:itemName

});

var$box=$(boxHtml).appendTo($boxContainer);box);

/*...*/

});

};

Whenre-implementingthegetAjaxTemplate()functiontouseHandlebars.js,theresultingcodeismostlythesameasbefore.TheonlydifferenceisintheinvocationoftheHandlebars.compile()methodinsteadoftheUndescore.jsequivalent.Thisisanaddedbenefitasmanyclient-sidetemplatingenginesinfluencedeachotherandhaveconvergedintoaverysimilarAPIregardingthewaythattheirtemplatefunctionsareused,largelybecauseofthepositiveuserfeedbackontheexistingimplementations.

functiongetAjaxTemplate(templateName){

/*…sameasbefore…*/

return$.ajax({/*…sameasbefore…*/}).then(function(template){

templateCache[templateName]=Handlebars.compile(template);

returntemplateCache[templateName];

});

}

NoteKeepinmindthatthe$.ajax()methodmightnotworkinsomebrowserswhenthepageisloadedthroughthefilesystem,butworksasintendedwhenservedusingawebserverlikeApache,IIS,ornginx.

Page 271: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

ModerationisbestinallthingsEventhoughthistechniquereducestheoveralldownloadfootprintofeachwebpage,italsoinevitablyincreasesthenumberofHTTPrequestsmade.Moreover,thepracticeofloadingeverytemplatelazilycansometimesincreasethetimethattheuserwillhavetowaitifthetemplatesarerequiredfortheinitialrenderingofthepage.

Balancingthewaythatweloadourtemplatesbetweenlazyloadingandembeddingthemin<script>tagsusuallybringsthebestofbothworlds.Thishybridapproachisconsideredabestpracticebytheindustrysinceitallowsustomicromanageandfinetuneeachimplementationbasedonitsneeds.Accordingtothispractice,thetemplatesthatarerequiredforthepresentationofthemaincontentofapageareembeddedinitsHTML,whiletherestofthemaredeliveredlazilywhenneeded,takingadvantageofbrowsercaching.

Theimplementationofsuchatemplateproviderfunctionisleftasanexerciseforthereader.Asahint,suchmethodshavetobeasynchronoussince,whentherequestedtemplateisnotfoundembeddedinthe<script>tagofthepage,itwillhavetoproceedandmakeanAJAXrequesttoretrieveitfromtheserver.

TipKeepinmindthatitisgenerallypreferabletogeneratethecompleteinitialHTMLcontentofthepageontheserversideinsteadofusingclient-sidetemplating.ThisnotonlyleadstoasmallerloadingtimeoftheinitialpagecontentbutitalsopreventssituationsinwhichtheuserispresentedwithanemptypagewhenJavaScriptisunavailableoranerrorhasoccurred.

Page 272: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 273: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

SummaryInthischapter,welearnedhowtousetwoofthemostcommonclient-sidetemplatinglibraries:Underscore.jsandHandlebars.js.WealsolearnedhowtheyallowustocreatecomplexHTMLtemplatesfasterwhilemakingourimplementationseasiertoreadandunderstand.Wethenwentontoanalyzetheirconventionsandevaluatetheirfeaturesandlearnedbyexamplehowtheycanbeeffectivelyandefficientlyusedinourimplementations.

Aftercompletingthischapter,wearenowabletogeneratecomplexHTMLstructuresinabrowserefficientlybyusingreadabletemplatesandutilizingtheuniquecharacteristicsofthetemplatinglibraries.

Inthenextchapter,wewilllearnhowtocreatejQueryPluginsasawaytoabstractpartsofourapplicationsintoreusableandextensibleimplementations.WewillintroducethemostwidelyusedpatternsfordevelopingjQueryPluginsandanalyzetheimplementationproblemsthateachofthemhelpstosolve.

Page 274: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 275: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

Chapter10.PluginandWidgetDevelopmentPatternsThischapterfocusesonthedesignpatternsandbestpracticesusedwhenimplementingjQueryPlugins.WewilllearnherehowtoabstractpartsofanapplicationintoseparatejQueryPlugins,promotingtheSeparationofConcernsprincipleandcodereusability.

WewillfirstlyanalyzethesimplestwaysthatajQueryPlugincanbeimplemented,learnthevariousconventionsofjQueryPlugindevelopmentandthebasiccharacteristicsthateverypluginshouldsatisfyinordertofollowjQueryprinciples.Wewillthenproceedwithanintroductiontothemostwidelyuseddesignpatternsandanalyzethecharacteristicsandbenefitsofeachofthem.Bytheendofthischapter,wewillbeabletoimplementextensiblejQueryPluginsusingthedevelopmentpatternthatbestsuitseachusecase.

Inthischapterwewill:

IntroducethejQueryPluginAPIanditsconventionsAnalyzethecharacteristicsthatmakeanexcellentpluginLearnhowtocreateapluginbyextendingthe$.fnobjectLearnhowtoimplementgenericpluginsthatareextensibleinordertomakethemreusableinmoreusecasesLearnhowtoprovideoptionsandmethodstoyourpluginsIntroducethemostcommondesignpatternsforjQueryplugindevelopmentandanalyzethecommonimplementationproblemsthateachofthemhelpstosolve

Page 276: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

IntroducingjQueryPluginsThekeyconceptofjQuerypluginsliesinextendingthejQueryAPIbymakingtheirfunctionalityaccessibleasamethodonjQueryCompositeCollectionObjects.AjQuerypluginissimplyafunctionthatisdefinedasanewmethodonthe$.fnobject,whichisthePrototypeObjectthateveryjQueryCollectionObjectinheritsfrom.

$.fn.simplePlugin101=function(arg1,arg2/*,...*/){

//Plugin'simplementation…

};

Bydefiningamethodonthe$.fnobject,weareactuallyextendingthecorejQueryAPIitself,sincethismakesthemethodavailableonallcreatedjQueryCollectionObjectsfromthatpointonwards.Asaresult,afterapluginhasbeenloadedinawebpage,itsfunctionalityisavailableasamethodoneveryobjectreturnedbythe$()function:

$('h1').simplePlugin101('test',1);

ThemainconventionofthejQuerypluginAPIisthatthejQueryCollectionObjectthatthepluginwasinvokedonismadeavailabletotheplugin’smethodasitsexecutioncontext.Inotherwords,wecanusethethisidentifierinthepluginmethod,asshownbelow:

$.fn.simplePlugin101=function(){

this.slideToggle();

//"this"isajQueryobjectwhereall

//jQuerymethodsareavailable

};

Page 277: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

FollowingjQueryprinciplesOneofthegoalswhencreatingapluginistomakeitfeellikeapartofjQueryitself.Afterreadingthepreviouschapters,youshouldbefamiliarwithsomeoftheprinciplesthatalljQuerymethodsfollowandthecharacteristicsthatmakeitsapproachspecial.ImplementingapluginthatfollowstheseprinciplesmakesusersfeelmorecomfortablewithitsAPI,bemoreproductive,andmakefewerimplementationerrors,whichleadstoanincreaseintheplugin’spopularityandadoption.

TwoofthemostimportantcharacteristicsthatagreatjQuerypluginshouldhaveareasfollows:

ItshouldapplyonalltheelementsofthejQueryCollectionObjectitisinvokedonwheneverapplicableItshouldallowfurtherchainingofotherjQuerymethods

Let’snowmoveonandanalyzeeachoftheseprinciples.

WorkingonCompositeCollectionObjectsOneofthemostimportantfeaturesofjQuerymethodsisthattheyareappliedoneveryitemoftheCompositeCollectionObjectthattheyareinvokedon.Asanexample,the$.fn.addClass()methodaddsoneormoreCSSclassestoeveryitemofthecollectionafterindividuallycheckingwhethereachclasshasalreadybeendefinedoneachindividualelement.

Asaresult,ourjQuerypluginsshouldalsofollowthisprinciplebyoperatingoneveryelementofacollection,whensuchathingseemslogical.IfyouareusingonlyjQuerymethodsinyourplugin’simplementation,mostofthetime,yougetthisforfree.Ontheotherhand,animportantconsiderationtobearinmindisthatnotalljQuerymethodsoperateoneveryelementofacollectionobject.Methodslike$.fn.html(),$.fn.css()and$.fn.data()applyonalltheitemsofthecollectionwhenusedassettermethods,butoperateonlyonthefirstelementwhenusedasgetters.

Let’sseeanexampleimplementationofapluginthatuses$.fn.animate()tocreateashakeeffectonallitemsofajQueryobject:

$.fn.vibrate=function(){

this.each(function(i,element){

//specificallyhandleeveryelement

var$element=$(element);

if($element.css('position')==='static'){

$element.css({position:'relative'});

}

});

this.animate({left:'+=3'},30)

.animate({left:'-=6'},60)

.animate({left:'+=6'},60)

.animate({left:'-=3'},30);

returnthis;//allowfurtherchaining

Page 278: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

};

Invokingthispluginwith$('button').vibrate();appliestheshakinganimationoneverymatchedelementofthepage.Toachievethat,thepluginchangestheleftCSSpropertyofallmatchedelementsusingthe$.fn.animate()method,whichconvenientlyoperatesoneveryelement.Ontheotherhand,sincethe$.fn.css()methodappliesonlyonthefirstelementofthecollectionwhenusedasagetter,wehadtoiterateoveralltheelementsusingthe$.fn.each()methodandensurethateachofthemwasnotstaticallypositioned,inwhichcasetheleftCSSpropertywouldnotaffectitsappearance.

Obviously,usingonlyjQuerymethodsisnotalwayssufficientfortheimplementationofaplugin.Inmostcases,anewpluginwillhavetouseatleastonenon-jQueryAPIforitsimplementation,requiringustoiterateovertheitemsofthecollectionandapplythelogicoftheplugintoeachofthemindividually.Thesameapproachshouldbeusedwheneachelementofthecollectionhastobehandledslightlydifferentlybasedonitsstate.

Asaresult,itisquitecommonforpluginstowrapalmostalloftheirimplementationsinsidea$.fn.each()invocation.Byrecognizingthecommonneedsthatarecoveredbyexplicititeration,thejQueryteamandmostjQuerypluginboilerplatesnowmakeitpartoftheirstandardpractice.

AllowingfurtherchainingIngeneral,whenyourplugin’scodedoesnotneedtoreturnanything,allthatyouhavetodotoenablefurtherchainingistoaddareturnthis;statementtoitslastline,aswesawinthepreviousexample.Makesurethatallthecodepathsreturnareferenceoftheinvocationcontext(this)oranotherrelevantjQuerycollectionobject,inthesamewaythat$.fn.parent()and$.fn.find()do.Alternatively,whenallyourcodeiswrappedinsideanotherjQuerymethod,suchas$.fn.each(),itiscommonpracticetosimplyreturntheresultofthatinvocation,asdemonstratedbelow:

$.fn.myLogPlugin=function(){

returnthis.each(function(i,element){

console.log($(element).text());

});

};

Keepinmindthat,ifyourcodemanipulatesthecollectionobjectthatitwasinvokedon,insteadofreturningthethisreference,youmightneedtoreturnthenewcollectionthatwastheresultofyourplugin’smanipulations.

NoteYoushouldavoidbasingyourplugin’simplementationonareturnvalueinordertoallowfurtherchaining.Insteadofdoingthat,itispreferabletoinitializethepluginonitsfirstinvocationandthenprovidesomeoverloadedwaystoinvokeit,asawayofreturningvalues.

Page 279: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

Workingwith$.noConflict()Thefirststeptoimproveaplugin’simplementationistomakeitworkinenvironmentsthatdonothaveaccesstothe$identifier.AnexampleofthisiswhenawebpageusesthejQuery.noConflict()method,whichpreventsjQueryfromassigningitselftothe$globalidentifier(orwindow.$)andkeepsitavailableonlyonthejQuerynamespace(window.jQuery).

NoteThejQuery.noConflict()methodallowsustopreventjQueryfromconflictingwithotherlibrariesandimplementationsthatalsohappentousethe$variable.Formoreinformation,youcanvisitthejQuerydocumentationpageat:http://api.jquery.com/jQuery.noConflict/

Insuchcases,theplugindefinitionwouldthrowan$isnotdefinederrororevenworse;itmighttrytousethe$variablethatthedeveloperhasreservedtouseinanimplementation,leadingtoerrorsthatarehardtodebug.

Fortunately,thechangesrequiredtofixthisproblemareeasytoimplementanddonotaffectthefunctionalityoftheplugin.Allthatwehavetodoisrenamealloftheoccurrencesofthe$identifierinourpluginwithjQuery,asshownbelow:

jQuery.fn.simplePlugin101=function(arg1,arg2/*,...*/){

var$buttons=jQuery('button');

//...

};

Page 280: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

WrappingwithanIIFEThenextbestpracticetofollowistowrapthedefinitionandimplementationofourpluginwithanIIFE.ThisnotonlymakesourpluginlookliketheModulePatternbutalsomakesourimplementationmorerobustbyaddingseveralotherbenefitstoit.

Firstofall,theIIFEpatternallowsustocreateanduseprivatevariablesandfunctionsinthecontextoftheplugin’sdefinition.Thesevariablesaresharedacrossalltheinstancesoftheplugininasimilarwaytohowstaticvariablesworkinotherprogramminglanguages,enablingustousethemassynchronizationpointsbetweentheplugininstances:

(function($){

varcallCounter=0;

functionutilityLogMethod(message){

if(window.console&&console.log){

console.log(message);

}

}

$.fn.simplePlugin101=function(arg1,arg2/*,...*/){

callCounter++;

utilityLogMethod(callCounter);

returnthis;

};

})(jQuery);

Otherwise,wewouldhavetousesomethinglike$.simplePlugin101._callCounteror$.simplePlugin101._utilityLogMethod()toemulateprivacy,whichisjustanamingconventionanddoesnotprovideanyactualprivacy.

Thesecondbenefit,asdemonstratedintheaboveexample,isthatitallowsustousethe$identifieragaintoaccessjQuerywithnoconcernsaboutconflicts.Inordertoachievethis,wearepassingthejQuerynamespacevariableasaninvocationparametertoourIIFEandusethe$identifiertonametherespectiveparameter.Inthisway,weeffectivelyaliasthejQuerynamespaceto$inthecontextcreatedbytheIIFE,enablingustousetheminimal$identifierinourimplementationtokeepourcodeslimandreadable,evenifjQuery.noConflict()isused.

Additionally,addingtheusestrict;statementonthetopofourIIFEhelpsustoeliminateanyleakingofvariablesintotheglobalnamespace.Forexample,thefollowingcodewouldthrowaReferenceError:assignmenttoundeclaredvariablexerrorduringtheinvocationoftheplugin’smethod,enablingustocatchthoseerrorsduringthedevelopmentphaseofthepluginhelpingproduceamorerobustfinalimplementation:

(function($){

'usestrict';

$.fn.leakingPlugin=function(){

x=0;//thereisno"varx"declaration,

//soanerroristhrownwhenexecuted

};

Page 281: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

})(jQuery);

$('div').leakingPlugin();

NoteFormoreinformationaboutJavaScript’sstrictexecutionmode,youcanvisit:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode

Finally,thispattern,aswithallthenamespacealiasingpracticesthatuseIIFEs,canalsohelpincreasethegainswhenminifyingyourplugin’ssourcecode,whencomparedtoanimplementationthatreferencesthejQuerynamespacevariabledirectly.Inanattempttomaximizethebenefitsofthistechnique,it’salsocommontoaliasalltheglobalnamespacevariablesthatourpluginaccesses,asdemonstratedbelow:

(function($,window,document,undefined){

//Plugin'simplementation…

})(jQuery,window,document);

Page 282: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 283: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

CreatingreusablepluginsAfteranalyzingthemostimportantaspectsofthedevelopmentofjQueryplugins,wearenowreadytoanalyzeanimplementationthatisusedforsomethingmorethanasimpledemonstration.Inordertocreateareallyusefulandreusableplugin,itmustbedesignedsuchthatitsoperationsarenotrestrictedbythedemandsofitsoriginalusecase.

Themostpopularplugins,likethemostusefuljQuerymethods,arethosethatprovideahighdegreeofconfigurationoftheirfunctionality.Creatingapluginthatisconfigurableaddsadegreeofflexibilitytoitsimplementation,whichenablesustomatchtheneedsofseveralotherusecasesthataregovernedbythesameoperationprinciples.

Aswesaidearlier,ajQuerypluginisjustafunctionattachedtothe$.fnobjectand,asaresult,wecanmakeitsimplementationmoreabstractandgenericinthesamewayaswithplainfunctionsofourmodules.Asinsimplefunctions,theeasiestwaytodifferentiatetheoperationofajQuerypluginisbyusinginvocationparameters.Apluginthatexposesalotofconfigurationparametershasgreatpotentialofbeingabletobematchtherequirementsofseveraldifferentusecases.

Page 284: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

AcceptingconfigurationparametersIncontrasttohowweimplementfunctionsthatusuallyacceptuptofiveargumentsandstillhaveamanageableandrelativelycleanAPI,thispracticedoesnotworksowellwithjQueryplugins.InordertoexposeaclearAPIandmaintainahighlevelofusability,regardlessofthevariousconfigurationoptionsthatareexposed,mostjQuerypluginsprovideaminimalAPIthatacceptsuptothreeinvocationarguments.Thisisachievedbyusingdedicatedsettingobjectswithaspecificformat,asawayofencapsulatingmultipleoptionsandpassingthemasasingleargument.AnotherapproachistoexposeanAPIwithtwoparameters,wherethefirstoneisaregularvaluethatdefinestheoperationofthepluginandthesecondoneisusedtowrapthelessimportantconfigurationoptions.

Agreatexampleofbothofthesepracticesisthe$.ajax(settings)method,whichisinvokedwithasinglesettingsobjectasaparametertodefinehowitshouldoperate,butalsoexposesanotheroverloadedwaytobeinvokedwithtwoarguments.Thetwoargumentoverloadisinvokedwith$.ajax(url,settings),wherethefirstisthetargetURLfortheHTTPrequestandthesecondisanobjectwiththerestconfigurationoptions.Whatappliestobothofthemisthatthemethoditselfcontainsasetofsensibledefaultsthatareusedinsteadofanyconfigurationparameterthattheuserhasnotdefined.Moreover,thesecondoverloadalsodefinesthesecondparameterasoptionaland,ifthatwasnotprovidedduringitsinvocation,itbasesitsoperationonthedefaultsettings.

Adoptingthesettingsobjectpracticeinourpluginsnotonlybringsalltheaforementionedbenefits,butalsoallowsustoextendtheimplementationinamorescalableway,sincetheadditionofanextraconfigurationparameterhaslittleeffectontherestofitsAPI.Asanexampleofthis,wewillreimplementthe$.fn.vibratepluginthatwesawearlierinthischapterinamoregenericway,sothatasettingobjectwithdefaultvaluesisusedforitsconfiguration:

(function($){

$.fn.vibrate=function(options){

varopts=$.extend({},$.fn.vibrate.defaultOptions,options);

this.each(function(i,element){

var$element=$(element);

if($element.css('position')==='static'){

$element.css({position:'relative'});

}

});

for(vari=0,len=opts.loops*4;i<len;i++){

varanimationProperties={};

varmovement=(i%2)?'+=':'-=';

movement+=(i===0||i===len-1)?

opts.amplitude/2:

opts.amplitude;

vart=(i===0||i===len-1)?

Page 285: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

opts.period/4:

opts.period/2;

animationProperties[opts.direction]=movement;

this.animate(animationProperties,t);

}

returnthis;

};

$.fn.vibrate.defaultOptions={

loops:2,

amplitude:8,

period:100,

direction:'left'

};

})(jQuery);

Incontrasttotheoriginalfixedimplementation,thisoneacceptsasingleobjectasaninvocationparameterwhichwrapsfourdifferentoptionsthatcanbeusedtodiversifytheoperationoftheplugin.Theoptionsobjectallowsustodiversifytheoperationofthepluginbyexposingfourcustomizationpoints:

ThenumberofloopsthattheshakeeffectshouldrunTheamplitudeoftheanimation,asameansofcontrollinghowmuchanelementshouldmoveawayfromitsoriginalpositionTheperiodofeachloop,asameansofcontrollinghowfastthemovementwillbeThedirectionoftheanimation,whichishorizontalwhenleftisusedorverticalwhentopisused

Byfollowingawidelyacceptedbestpractice,wehavedefinedallthedefaultvaluesfortheconfigurationoptionsasaseparateobject.Thispatternnotonlyallowsustogatheralltherelatedvaluesunderasingleobject,butalsoenablesustousethe$.extend()methodasaneffectivewayofcomposingallthedefinedoptionswiththedefaultvaluesoftheundefinedones.Wecanthusavoidcheckingexplicitlyfortheexistenceofeachindividualproperty,reducingthecomplexityandthesizeofourcode.

Inbrief,the$.extend()methodreturnstheobjectpassedasitsfirstargumentaftermergingthepropertiesofthesubsequentobjectstogetherintothefirstobject.Asaresult,thereturnedobjectwillcontainallthedefaultvaluesexceptthosethatweredefinedintheoptionsobjectthatwaspassedasaninvocationparameter.

NoteFormoreinformationaboutthe$.extend()helpermethod,youcanvisitthedocumentationpageat:http://api.jquery.com/jQuery.extend/

Moreover,insteadofusingasimplevariable,weareexposingthedefaultoptionsobjectasapropertyoftheplugin’sfunction,enablinguserstochangethemtobettersuittheirneeds.Asanexample,consideracaseinwhichasmoothanimationisrequiredfortheneedsofaspecificapplication.Bysetting$.fn.vibrate.defaultOptions.period=250,thedeveloperwouldcompletelyremovetheneedtospecifytheperiodoptionin

Page 286: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

everyinvocationoftheplugin,whichwouldleadtoanimplementationwithlessrepetitivecode.

NoteThejQuerylibraryitselfadoptsthispracticefordefiningthedefaultconfigurationparametersofthe$.ajax()method.Becauseoftheincreasedcomplexityofthismethod,jQueryprovidesuswiththejQuery.ajaxSetup()methodasawayofsettingupthedefaultparametersforeveryAJAXrequest.

Finally,inordertocreateagenericvariantoftheoriginalimplementationandutilizetheaforementionedconfigurationoptions,wereplacedthefourfixedinvocationsofthe$.fn.animate()methodoftheoriginalimplementationwithaforloopthatutilizedtheloopsoption.Insidetheforloopitself,weconstructtheparametersforeachcallofthe$.fn.animate()methodandbrieflyalternatethedirectionoftheanimatedmovementoneachsubsequentexecutionoftheloop,andalsoensurethatthefirstandlastmovementshavehalfofthetimedurationandhalfoftheshiftofalloftheothersteps.

Thefinalimplementationcanbeconfiguredtoproducedifferentanimations,basedontheneedsofeachspecificusecase,rangingfromshorthorizontalanimationsthatareidealfornotifyingauseraboutaninvalidaction,toverticallonganimationsthatlooklikealevitationeffect.Theplugincanbeinvokedwithanycombinationoftheaforementionedoptions,usethedefaultvaluesformissingoptionsandevenoperatewithnoinvocationargument,asshownbelow:

//dothedefaultintenseanimationonabutton

//thatappearsdisabled,todesignateaninvalidaction

$('button.disabled').on('click',function(){

$(this).vibrate();

});

//doasmothershakeanimationtocatchtheuser's

//attentiononanimportantpartofthepage

$('.save-button').vibrate({loops:3,period:250});

//startalongrunninglevitationeffectontheheaderofthepage

$('h1').vibrate({direction:'top',loops:1000,period:5000});

Page 287: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

WritingstatefuljQuerypluginsThepluginimplementationsthatwehavelookedatsofarwerestatelesssince,aftercompletingtheirexecution,theyreverttheirmanipulationsontheDOM’sstateanddon’tleaveallocatedobjectsinthebrowser’smemory.Asaresult,subsequentinvocationsofstatelesspluginsalwaysproducethesameresults.

Asyoucanprobablyguess,suchpluginshavelimitedapplicationssincetheycan’tbeusedtocreateaseriesofcomplexinteractionswiththeuserofthewebpage.Inordertoorchestratecomplexuserinteractions,apluginneedstopreserveaninternalstatewiththeactionstakenuptothatpointinordertochangeitsoperationmodeappropriatelyandhandlesubsequentinteractions.Comparingthecharacteristicofstatefulandstatelesspluginscouldbedefinedastheequivalenttocomparingplain(static)functionswithmethodsthatarepartofanobjectandcanoperateonitsstate.

Anotherpopularcategoryofplugins,inwhichhavinganinternalstateisessential,isthefamilyofpluginsthatmanipulatetheDOMtree.Thesepluginsusuallycreatecomplexelementstructuressuchasarichtexteditors,datepickersandcalendars,commonlybybuildingonauser-definedempty<div>element.

Page 288: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

ImplementingastatefuljQueryPluginAsanexampleofthepatternsusedfortheimplementationofpluginsofthisfamily,wewillwriteagenericElementMutationObserverplugin.ThispluginwillprovideuswithaconvenientwayofaddingeventlistenersforchangestotheDOMtreethatoriginatefromanyoftheelementsthatthispluginwasinvokedon.Asawayofachievingthat,thefollowingimplementationusestheMutationObserverAPI,which,atthetimeofwriting,isimplementedbyallmodernbrowsersandisavailabletomorethan86%ofwebusers.

NoteFormoreinformationontheMutationObserver,youcanvisit:https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver

Let’snowproceedwiththeimplementationandanalyzethepracticesthatwereused:

(function($){

$.fn.mutationObserver=function(action){

returnthis.each(function(i,element){

var$element=$(element);

varinstance=$element.data('plugin_mutationObserver');

if(!instance){

varobserver=newMutationObserver(function(mutations){

mutations.forEach(function(mutation){

instance.callbacks.forEach(function(callbackFn){

callbackFn(mutation);

});

});

});

observer.observe(element,{

attributes:true,

childList:true,

characterData:true

});

instance={

observer:observer,

callbacks:[]

};

$element.data('plugin_mutationObserver',instance);

}

if(typeofaction==='function'){

instance.callbacks.push(action);

}

});

};

})(jQuery);

Firstly,wedefineourplugininsideanIIFE,asrecommendedearlierinthischapter.Rightafterthedeclarationofthepluginonthe$.fnobject,weusethe$.fn.each()methodasa

Page 289: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

directapproachtoensurethatthefunctionalityofourpluginisappliedtoeveryitemofthejQueryCollectionObjectthatitwasinvokedon.

Twoofthemainissuesthatstatefulpluginimplementationshaveisthelackofamechanismtopreservetheinternalstateofeachinstantiationofthepluginandawayofavoidingbeinginitializedmanytimesonthesamepageelement.Inordertosolvebothoftheseproblems,weneedtousesomethinglikeahashtableinwhichthekeyistheelementitselfandthevalueisanobjectwiththestateoftheplugin’sinstance.

Fortunately,thisismoreorlesshowthe$.fn.data()methodworksbyassociatingDOMelementsandJavaScriptobjectvaluesusingspecificstringkeys.Byusingthe$.fn.data()methodandtheplugin’snameasanassociationkey,weareabletostoreandretrievethestateobjectofourpluginveryeasily.

TipUsingthe$.fn.data()methodforthisusecaseisconsideredabestpracticeandisusedbymoststatefulpluginimplementationsandboilerplatessinceitisarobustpartofjQuerythatenablesustoreducethesizeofourplugin’simplementation.

Ifanexistingstateobjectisnotfoundthenwecanassumethatthepluginisnotyetinitializedonthatspecificelementandstartitsinitializationrightaway.ThestateobjectofthispluginwillcontaintheinstanceoftheactiveMutationObserverresponsiblefortrackingthechangesthathappenontheobservedDOMelement,andanarraywithallthecallbacksthathavesubscribedtoittogetnotificationsaboutchanges.

AftercreatinganewMutationObserverinstance,weconfigureittolookforthreespecifictypesofDOMchangesandinstructittoinvokeallthecallbacksoftheplugin’sstateobjectwheneversuchDOMchangesoccur.Finally,wecreatethestateobjectitselftoholdtheobserverandtheassociatedcallbacksandusethe$.fn.data()methodasasetterandassociateitwiththepageelement.

Afterensuringthatthepluginisinstantiatedandinitializedontheprovidedelement,wecheckwhetherthepluginisinvokedwithafunctionasaparameterand,ifso,weaddittothelistoftheplugin’scallbacks.

TipKeepinmindthatusingasingleMutationObserverinstanceperelementandhavingitnotifyaboutDOMchangesbyiteratingoveranarrayofcallbacksgreatlyreducesthememoryrequirementsoftheimplementation,justlikewhenweareusingasingledelegateobserver.

AnexampleofusingournewlyimplementedplugintoobserveforchangesofaspecificDOMelementwouldlooklikethis:

$('.container').mutationObserver(function(mutation){

console.log('SomethingchangedontheDOMtree!');

});

Page 290: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

DestroyingaplugininstanceAnextraconsiderationthatastatefulpluginhastotakeintoaccountisofferingthedeveloperawaytoreversethechangesthatitintroducedtothestateofthepage.ThemostcommonandsimpleAPIforachievingthisistoinvokethepluginwiththedestroyliteralasitsfirstparameter.Let’sproceedwiththerequiredimplementationchanges:

(function($){

$.fn.mutationObserver=function(action){

returnthis.each(function(i,element){

var$element=$(element);

varinstance=$element.data('plugin_mutationObserver');

if(action==='destroy'&&instance){

instance.observer.disconnect();

instance.observer=null;

$element.removeData('plugin_mutationObserver');

return;

}

if(!instance){

/*...*/

}

});

};

})(jQuery);

Inordertoadaptourimplementationtotheaboverequirement,allwehadtodowastocheckwhetherthepluginwasinvokedwiththedestroystringvalueasitsfirstparameter,rightafterretrievingtheplugin’sstateobject.Ifwefindthatthepluginhasalreadybeeninstantiatedonthespecifiedelementandthatthedestroystringvaluehasbeenused,wecanproceedtostoptheMutationObserveritselfandcleartheassociationthat$.fn.data()createdbyusingthe$.fn.removeData()method.Finally,attheendoftheifstatementweaddedareturnstatementsince,aftercompletingthedestructionoftheplugininstance,wenolongerneedtoexecuteanyothercode.Anexampleofdestroyingaplugininstancewiththisimplementationwouldlooklikethis:

$('.container').mutationObserver('destroy');

Page 291: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

ImplementinggetterandsettermethodsByusingthesametechniquethatwedemonstratedearlierfortheimplementationofthedestroymethodofourplugin,wecanprovideseveralotheroverloadedwaystoinvokeourpluginthatworklikenormalmethods.ThispatternisnotonlyusedbyplainjQueryplugins,butisalsoadoptedbymorecomplexpluginarchitectures,aswithjQuery-UI.

Ontheotherhand,wemightendupwithapluginimplementationthatresultsinalargenumberofinvocationoverloads,whichissomethingthatwouldmakeitdifficulttouseanddocument.AwaytoworkaroundthisistocombinethegetterandsettermethodsofyourAPIintomulti-purposemethods.ThisnotonlyreducestheAPIsurfaceofyourpluginsothatadeveloperhastorememberfewermethodnamesbutitalsoincreasestheproductivitysincethesamepatternisusedinmanyjQuerymethodslike$.fn.html(),$.fn.css(),$.fn.prop(),$.fn.val(),and$.fn.data().

Asademonstrationofthis,let’sseehowwecanaddanewmethodtoourMutationObserverpluginthatworksbothasagetterandasetterfortheregisteredcallbacks:

(function($){

$.fn.mutationObserver=function(action,callbackFn){

varresult=this;

this.each(function(i,element){

var$element=$(element);

varinstance=$element.data('plugin_mutationObserver');

/*...*/

if(typeofaction==='function'){

instance.callbacks.push(action);

}elseif(action==='callbacks'){

if(callbackFn&&callbackFn.length>=0){

//usedasasetter

instance.callbacks=callbackFn;

}else{

//usedasagetterforthefirstelement

result=instance.callbacks;

returnfalse;//breakthe$.fn.each()iteration

}

}

});

returnresult;

};

})(jQuery);

Asshownintheabovecode,wehavecreatedanoverloadedinvocationmethodwhichusesthecallbacksstringvalueasthefirstargumentoftheplugininvocation.ThisgetterandsettermethodallowsustoretrieveoroverwriteallofthecallbacksthatareregisteredontheMutationObserverandworksinadditiontothepre-existingmethodsforinvokingtheplugin,byusingafunctionparameterandthedestroymethod.

Page 292: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

Thegetterandsetterimplementationisbasedontheassumptionthat,whentryingtousethecallbacksmethodasagetter,youdon’tneedtopassanyextraparametersand,whentryingtouseitasasetter,youwillpassanextraarrayasaninvocationparameter.Inordertosupportthegettervariant,whichpreventsfurtherchainingandonlyoperatesonthefirstelementofthecompositecollection,wehadtodeclareandusetheresultvariablewhichisinitializedtothevalueofthethisidentifier.Ifthecallbacksgetterisused,weassignthecallbacksofthefirstelementofthecollectiontotheresultvariableandbreakoutofthe$.fn.each()iterationbyreturningfalsetofinishtheexecutionoftheplugin’smethod.

Hereisanexampleusecaseforournewlyimplementedgetterandsettermethod:

//retrievethecallbacks

varoldCallbacks=$('.container').mutationObserver('callbacks');

//clearthem

$('.container').mutationObserver('callbacks',[]);

//addanewone

$('.container').mutationObserver(function(){

console.log('Printedonlyonce');

//restoretheoldcallbacks

$('.container').mutationObserver('callbacks',oldCallbacks);

});

TipKeepinmindthatinvocationoverloadsthatpreventfurtherchainingbyreturningnon-jQueryobjectresultsshouldbewelldocumentedsincethistechniqueconflictswiththechainingprinciplethateveryoneexpectstowork.

Page 293: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

UsingourplugininourDashboardapplicationAftercompletingourmutationObserverplugin,letsnowseehowwecanuseitfortheimplementationofthecountersub-modulethatweusedinourDashboard’simplementationinpreviouschapters:

(function(){

'usestrict';

dashboard.counter=dashboard.counter||{};

var$counter;

dashboard.counter.init=function(){

$counter=$('#dashboardItemCounter');

var$boxContainer=dashboard.$container

.find('.boxContainer');

$boxContainer.mutationObserver(function(mutation){

dashboard.counter.setValue($boxContainer.children().length);

});

};

dashboard.counter.setValue=function(value){

$counter.text(value);

};

})();

Asyoucanseeintheaboveimplementation,ourpluginabstractsnicelyandreplacestheoldimplementationbyprovidingageneric,flexibleandreusableAPI.Insteadoflisteningforclickeventsonthedifferentbuttonsofthepage,theimplementationisnowusingthemutationObserverpluginandobservestheboxContainerelementfortheadditionsorremovalsofchildelements.Moreover,thisimplementationchangedoesnotaffectthefunctionalityofthecountermodulewhichappearstoworkinthesamewaysinceallthechangesareencapsulatedinthemodule.

Page 294: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 295: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

UsingthejQueryPluginBoilerplateThejQueryBoilerplateproject,whichisavailableathttps://github.com/jquery-boilerplate/jquery-patterns,offersseveraltemplatesthatcanbeusedasstartingpointsfortheimplementationofrobustandextensibleplugins.Thesetemplatesincorporatealotofbestpracticesanddesignpatternssuchasthoseanalyzedearlierinthischapter.Eachofthetemplatespacksanumberofbestpracticesthatworkwelltogether,inanattempttoprovidegoodstartingpointsthatbettermatchthevarioususecases.

Perhapsthemostwidelyusedtemplateisjquery.basic.plugin-boilerplatefromAdamSontagandAddyOsmani,whicheventhoughitischaracterizedasagenerictemplateforbeginnersandabove,successfullycoversmostaspectsofjQueryplugindevelopment.WhatmakesthistemplateuniqueistheObject-Orientedapproachthatitfollowswhichispresentedinsuchawaythatithelpsyouwritebetterstructuredcode,withoutmakingithardertointroducecustomizationsontheimplementation.Let’sproceedandanalyzeitssourcecode:

/*!

*jQuerylightweightpluginboilerplate

*Originalauthor:@ajpiano

*Furtherchanges,comments:@addyosmani

*LicensedundertheMITlicense

*/

;(function($,window,document,undefined){

varpluginName="defaultPluginName",

defaults={

propertyName:"value"

};

functionPlugin(element,options){

this.element=element;

this.options=$.extend({},defaults,options);

this._defaults=defaults;

this._name=pluginName;

this.init();

}

Plugin.prototype={

init:function(){/*Placeinitializationlogichere*/},

yourOtherFunction:function(options){/*somelogic*/}

};

//Areallylightweightpluginwrapperaroundtheconstructor,

//preventingagainstmultipleinstantiations

$.fn[pluginName]=function(options){

returnthis.each(function(){

if(!$.data(this,"plugin_"+pluginName)){

$.data(this,"plugin_"+pluginName,

newPlugin(this,options));

}

});

};

})(jQuery,window,document);

Page 296: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

Thesemi-colonrightbeforetheIIFEistheretoavoiderrorsincaseofunfortunatescriptconcatenation(andpossiblyminification)withafilethatmightbemissinganendingsemi-colon.Rightbelow,theboilerplateusesthepluginNamevariableasaDRYwayofnamingourpluginandusingitsnameforanyothercase.Asanaddedbenefit,allthatwehavetodoifweneedtorenameourpluginischangethevalueofthisvariableandrenamethe.jsfileofourpluginaccordingly.

Followingthebestpracticesthatwesawearlier,avariableisusedtoholdthedefaultoptionsofthepluginand,aswecanseeafewlineslater,itismergedwiththeuser-providedoptionsusingthe$.extend()method.Keepinmindthat,ifwewanttoexposethedefaultoptions,allthatwehavetodoisdefineitaspartoftheplugin’snamespace:$.fn[pluginName].defaultOptions=defaults;

Theactualplugindefinitioncanbefoundneartheendofthisboilerplatecode.Followingthealreadydiscussedbestpractices,ititeratesovertheitemsofthecollectionusing$.fn.each()andreturnsitsresult,whichisequivalenttoreturningthis.Itthenensuresthatapluginstateinstanceexistsforeachitemofthecollectionbyusingthe$.data()methodandtheprefixedpluginnameasanassociationkey.

ThePluginconstructorfunctionisusedforthecreationoftheplugin’sstateobjectwhich,afterstoringtheDOMelementandthefinalpluginoptionsaspropertiesoftheobject,invokestheinit()methodofitsprototype.Theinit()methodisthesuggestedplacetodefineourinitializationcode,forexample,itcouldinstantiateanewMutationObserveraswedidearlierinthischapter.

Page 297: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

AddingmethodstoyourpluginBydefault,everymethodthatisdefinedaspartoftheprototypeisonlyavailableforinternaluse.Ontheotherhand,wecaneasilyextendtheaboveimplementationtomakeamethodavailabletoallourusers,asshownbelow:

$.fn[pluginName]=function(options,extraParam){

returnthis.each(function(){

varinstance=$.data(this,"plugin_"+pluginName);

if(!instance){

instance=newPlugin(this,options);

$.data(this,"plugin_"+pluginName,instance);

}elseif(options==='yourOtherFunction'){

instance.yourOtherFunction(this,extraParam);

}

});

};

OneguidelinetofollowwhenworkingwiththisboilerplateistoextendyourpluginbyaddingextramethodstothePlugin‘sprototype.Additionally,trytokeepanymodificationstotheplugin’sdefinitionassmallaspossible,ideallysinglelinemethodinvocations.

Inordertomaketheimplementationmorescalable,withregardstohowthepluginmethodsareinvokedandifwewanttoaddanabstractapproachformethodsthatareintendedforinternalorprivateusebytheplugin,wecanintroducethefollowingchanges:

$.fn[pluginName]=function(options){

varrestArgs=Array.prototype.slice.call(arguments,1);

returnthis.each(function(){

varinstance=$.data(this,"plugin_"+pluginName);

if(!instance){

instance=newPlugin(this,options);

$.data(this,"plugin_"+pluginName,instance);

}elseif(typeofoptions==='string'&&//methodname

options[0]!=='_'&&//protectprivatemethods

typeofinstance[options]==='function'){

instance[options].apply(instance,restArgs);

}

});

};

Intheaboveimplementation,weusedthefirstargumenttoidentifythemethodthatneedstobeinvokedandtheninvokeditwiththerestarguments.Wealsoaddedachecktopreventtheinvocationofmethodsthatstartwithanunderscorewhich,accordingtocommonconventions,areintendedtobeforinternalorprivateuse.Asaresult,inordertoaddanextramethodtoyourplugin’spublicAPI,wejustneedtodeclareitinthePlugin.prototypethatwesawearlier.

NoteAnothergreatwaytoimplementyourpluginwhenyouarealreadyusingjQuery-UIinyourapplicationistousethe$.widget()methodwhichisalsoknownasjQuery-UI

Page 298: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

WidgetFactory.Itsimplementationabstractsseveralpartsoftheboilerplatecodethatwesawinthischapterandhelpscreatecomplexandrobustplugins.Formoreinformation,youcanreadthedocumentationat:http://api.jqueryui.com/jQuery.widget/

Page 299: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 300: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

ChoosinganameLastly,afterlearningthebestpracticesthatweneedtocreateajQueryplugin,let’ssaysomethingaboutthenamingconventionsandwheretopublishyournewandshinyplugin.

Asyouhaveprobablyalreadyseen,mostjQuerypluginsusethefollowingnamingconvention:jQuery-myPluginNamefortheirprojectsitesandrepositoriesandstoretheirimplementationsinafilenamedjquery.mypluginname.js.Aftersettlingonsomeprospectivenamesforyourplugin,takeamomentandsearchthewebtoverifythatthereisnooneelsewiththesameprojectname.ThejQuerydocumentationsuggestssearchingforpluginsonNPMandrefiningyourresultsbyusingthejquery-pluginkeyword.Thisisobviouslythebestwaytopublishyourpluginsothatitcanbeeasilyfoundbyothers.

NoteFormoreinformationaboutNPM,youcanvisit:https://www.npmjs.com/

AnotherpopularplaceforsearchingandhostingJavaScriptlibrariesisGitHub.Youcanfinditsrepositorysearchpageathttps://github.com/search?l=JavaScript,whereitfiltersthesearchresultstoincludeonlyJavaScriptprojectsandsearchesforexistingpluginsandalreadyusedprojectnames.SinceinourcasewearefocusingonjQueryplugins,youwillgetbetterresultsbysearchingforprojectnamesthatfollowtheaforementionednamingconvention,jQuery-myPluginName.

NoteUntilrecently,developerscouldsearchforexistingpluginsandregisteranewoneattheofficialjQueryPluginRegistry(http://plugins.jquery.com/).Unfortunately,ithasbeendiscontinuedandnowonlyallowssearchingforolderpluginswithnonewsubmissions.

Page 301: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 302: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

SummaryInthischapterwelearnedhowjQuerycanbeextendedbyimplementingandusingplugins.WefirstsawanexampleofthesimplestwaythatajQueryplugincanbeimplementedandanalyzedthecharacteristicsthatmakeagreatplugin,andonewhichfollowstheprinciplesofthejQuerylibrary.

WewerethenintroducedtothemostcommondevelopmentpatternsinthedevelopercommunityforcreatingjQueryPlugins.Weanalyzedtheimplementationproblemsthateachofthemsolvesandtheusecasesthatareabettermatchforthem.

Aftercompletingthischapter,wearenowabletoabstractpartsofourapplicationsintoreusableandextensiblejQuerypluginsthatarestructuredusingthedevelopmentpatternthatbestmatcheseachusecase.

Inthenextchapter,wewillpresentseveraloptimizationtechniquesthatcanbeusedtoimprovetheperformanceofourjQueryapplications,especiallywhentheybecomelargeandcomplex.WewilldiscusssimplepracticessuchasusingCDNstoloadthird-partylibrariesandcontinuewithmoreadvancedsubjectssuchaslazyloadingthemodulesofanimplementation.

Page 303: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 304: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

Chapter11.OptimizationPatternsThischapterpresentsseveraloptimizationtechniquesthatcanbeusedtoimprovetheperformanceofjQueryapplications,especiallywhentheybecomelargeandcomplex.

WewillstartwithsimplepracticeslikebundlingandminifyingourJavaScriptfilesanddiscussthebenefitsofusingCDNstoloadthird-partylibraries.WewillthenmoveontoanalyzesomesimplepatternsforwritingefficientJavaScriptcodeandlearnhowtowriteefficientCSSselectorsinordertoimprovethepage’srenderingspeedandDOMtraversalsusingjQuery.

WewillthenstudyjQuery-specificpracticessuchasthecachingofjQueryCompositeCollectionObjects,howtominimizeDOMmanipulations,andhaveareminderoftheDelegateObserverPatternasagoodexampleoftheFlyweightPattern.Lastly,wewillgetanintroductiontotheadvancedtechniqueofLazyLoadingandhaveademonstrationofhowtoloadthedifferentmodulesofanimplementationprogressively,basedonuseractions.

Bytheendofthischapter,wewillbeabletoapplythemostcommonoptimizationpatternstoourimplementationsandusethischapterasachecklistofbestpracticesandperformancetipsbeforemovingtheapplicationtoaproductionenvironment.

Inthischapter,weshall:

LearnthebenefitsofbundlingandminifyingourJavaScriptfilesLearnhowtoloadthird-partylibrariesthroughtheCDNserverLearnsomesimpleJavaScriptperformancetipsLearnhowtooptimizeourjQuerycodeIntroducetheFlyweightpatternandshowcasesomeexamplesofitLearnhowtolazyloadpartsofourapplicationwhenrequiredbyauseraction

Page 305: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

PlacingscriptsneartheendofthepageThefirsttipformakingyourpage’sinitialrenderingfasteristogatheralltherequiredJavaScriptfilesandplacetheir<script>tagsneartheendofthepage,preferablyjustbeforetheclosing</body>tag.Thischangewillhaveagreatimpactonthetimeneededfortheinitialrenderingofthepage,especiallyforuserswithlowspeedconnectionssuchasmobileusers.Ifyouarealreadyusingthe$(document).ready()methodforallinitializationpurposesthatrelatetotheDOM,movingthe<script>tagsaroundshouldnotaffectthefunctionalityofyourimplementationatall.

Themainreasonforthisisthat,eventhoughbrowsersdownloadthepage’sHTMLandotherresources(CSS,images,andsoon)inparallel,whena<script>tagisencountered,thebrowserpauseseverythingelseuntilitisdownloadedandexecuted.Inordertoworkaroundthislimitationofthespecification,attributeslikedeferandasyncfromHTLM5havebeenintroducedaspartsofthe<script>tagspecificationbutunfortunatelyhaveonlystartedtobeadoptedbysomebrowsersrecently.Asaresult,thispracticeisstillwidelyusedtoobtaingoodpageloadingspeedsevenonolderbrowsers.

NoteFormoreinformationaboutthe<script>tagyoucanvisit:https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script

Page 306: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 307: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

BundlingandminifyingresourcesThefirstplacetolookwhentryingtomakeapageloadfasterisforwaystoreducethenumberandtotalsizeofHTTPrequests.Thebenefitscomefromthefactthatthebrowserdownloadsthecontentinlargerchunksinsteadofspendingtimewaitingforalotofsmallround-tripstotheservertocomplete.Thisisespeciallybeneficialforuserswithlowspeedconnectionssuchasmobileusers.

Resourceconcatenationisasimpleconceptthatdoesnotneedanyintroduction.Thiscanbedonemanuallybutitispreferabletoautomatethistaskwithabundlingscriptorintroduceabuildstepforyourproject.Dependingonyourdevelopmentenvironment,therearedifferentbundlingsolutionstochoosefrom.Ifyouareusinggruntorgulpaspartofyourdevelopmentstack,youcanusesolutionslikegrunt-contrib-concat(https://github.com/gruntjs/grunt-contrib-concat)andgulp-concat(https://github.com/contra/gulp-concat)respectively.

MinifyingJavaScriptfilesisamorecomplexprocedurewhichincludesaseriesofcodetransformationsthatareappliedtothetargetsourcecode,rangingfromsomethingassimpleaswhitespaceremovaltomorecomplextaskslikevariablerenaming.PopularsolutionsforminifyingJavaScriptinclude:

YUICompressoravailableathttp://yui.github.io/yuicompressor/Google’sClosureCompileravailableathttps://developers.google.com/closure/compiler/UglifyJSavailableathttps://github.com/mishoo/UglifyJS2

Onceagain,varioussolutionsexistthatintegratetheabovelibrariesnicelywithyourpreferreddevelopmentenvironmentandmakeminificationasimpletask.Examplesofintegrationsforgruntandgulpincludegrunt-contrib-uglify(https://github.com/gruntjs/grunt-contrib-uglify)andgulp-uglify(https://github.com/terinjokes/gulp-uglify)respectively.

Asafinalword,keepinmindthatyourcodeshouldbeasreadableandaslogicallystructuredaspossible.BundlingandminifyingyourJavaScriptandCSSfilesismosteffectivelydoneasabuildstepofyourdevelopmentanddeploymentprocedures.

Page 308: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

UsingIIFEparametersApartfromhelpingtoavoidpollutingtheglobalnamespace,usingIIFEstowrapyourimplementationcanalsobebeneficialforthesizeofyourminifiedJavaScriptfiles.Let’stakealookatthefollowingcodeinwhichthejQuery,thewindow,andthedocumentvariablesarepassedasinvocationparameterstothemodule’sIIFE.

(function($,window,document,undefined){

if(window.myModule===undefined){

window.myModule={};

}

myModule.init=function(){/*...*/};

$(document).ready(myModule.init);

})(jQuery,window,document);

Wesawasimilarpatterninthepreviouschapter,aspartofthesuggestedtemplateforcreatingjQueryplugins.Eventhoughthevariablealiasingdoesnotaffectthefunctionalityoftheimplementation,itallowsthecodeminifierstoapplyvariablerenaminginmoreplacesthanbefore,resultingincodelikethefollowing:

(function(b,a,c,d){

a.myModule===d&&(a.myModule={});

myModule.init=function(){/*...*/};

b(c).ready(myModule.init);

})(jQuery,window,document);

Asyoucanseeintheabovecode,alltheinvocationparametersoftheIIFEwererenamedbytheminifiertosingleletteridentifiers,whichincreasesthegainsoftheminificationespeciallyiftheoriginalidentifiersareusedinseveralplaces.

TipAsanaddedbenefit,aliasingalsoprotectsourmodulesfromthecasethattheoriginalvariablesgetaccidentallyassignedadifferentvalue.Forexample,whenIIFEparametersarenotused,anassignmentlike$={}orundefined=7fromwithinadifferentmodulewouldbreakalltheimplementation.

Page 309: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 310: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

UsingCDNsInsteadofservingalloftheJavaScriptandCSSfilesofthethird-partylibrariesfromyourwebserver,youshouldconsiderusingaContentDeliveryNetwork(CDN).UsingaCDNtoservethestaticfilesofthelibrariesthatareusedbyyourwebsitecanmakeitloadfastersince:

CDNshavehighspeedconnectionsandseveralcachinglevels.CDNshavemanygeographicallydistributedserversthatcandelivertherequestedfilesfastersincetheyareclosertotheenduser.CDNshelpparallelizeresourcerequests,sincemostbrowserscanonlydownloaduptofourresourcesconcurrentlyfromanyspecificdomain.

Moreover,ifauserhasstaticresourcescachedfromapreviousvisittoanotherwebsitethatusesthesameCDN,heorshewillnothavetodownloadthemagain,reducingthetimethatyoursiteneedstoload.

BelowisalistwiththemostwidelyusedCDNsforJavaScriptlibrarieswhichyoucanuseinyourimplementations:

https://code.jquery.com/https://developers.google.com/speed/libraries/https://cdnjs.com/http://www.jsdelivr.com/

Page 311: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

UsingJSDelivrAPIAnewcomertotheCDNworldisJSDelivr,whichisgainingpopularitybecauseofitsuniquefeatures.Beyondsimplyservingexistingstaticfiles,JSDelivrprovidesanAPI(https://github.com/jsdelivr/api)thatallowsustocreateandusecustombundleswiththeresourcesthatweneedtoload,helpingustominimizetheHTTPrequeststhatoursiteneeds.Moreover,itsAPIallowsustotargetlibrarieswithdifferentlevelsofspecificity(major,minor,orbugfixreleases)andevenallowsustoloadonlyspecificpartsofalibrary.

Asanexample,takealookatthefollowingURL,whichallowsustoloadthemostrecentbugfixreleasesofjQueryv1.11.xwithasinglerequestaswellassomepartsofjQuery-UIv1.10.xandBootstrapv3.3.x:http://cdn.jsdelivr.net/g/[email protected],[email protected](jquery.ui.core.min.js+jquery.ui.widget.min.js+jquery.ui.mouse.min.js+jquery.ui.sortable.min.js),[email protected]

Page 312: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 313: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

OptimizingcommonJavaScriptcodeInthissection,wewillanalyzesomeperformancetipsthatarenotjQuery-specificandcanbeappliedtomostJavaScriptimplementations.

Page 314: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

WritingbetterforloopsWheniteratingovertheitemsofanarrayoranarray-likecollectionwithaforloop,asimplewaytoimprovetheperformanceoftheiterationistoavoidaccessingthelengthpropertyoneveryloop.Thiscaneasilybedonebystoringtheiterationlengthtoaseparatevariable,declaredjustbeforethelooporevenalongwithit,asshownbelow:

for(vari=0,len=myArray.length;i<len;i++){

varitem=myArray[i];

/*...*/

}

Moreover,ifweneedtoiterateovertheitemsofanarraythatdoesnotcontainfalsyvalues,wecanuseanevenbetterpatternwhichiscommonlyappliedforiteratingoverarraysthatcontainobjects:

varobjects=[{},{},{}];

for(vari=0,item;item=objects[i];i++){

console.log(item);

}

Inthiscase,insteadofrelyingonthelengthpropertyofthearray,weexploitthefactthataccesstoanout-of-boundspositionofthearrayreturnsundefinedwhichisfalsyandstopstheiteration.AnothersamplecasethatthistrickcanbeusediniswheniteratingoverNodeListsorjQueryCompositeCollectionObjectsasshownbelow:

varanchors=$('a');//ordocument.getElementsByTagName('a');

for(vari=0,anchor;anchor=anchors[i];i++){

console.log(anchor.href);

}

NoteFormoreinformationaboutthetruthyandfalsyJavaScriptvalues,visit:https://developer.mozilla.org/en-US/docs/Glossary/Truthyandhttps://developer.mozilla.org/en-US/docs/Glossary/Falsy

Page 315: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 316: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

WritingperformantCSSselectorsEventhoughSizzle(jQuery’sselectorengine)hidesthecomplexityofDOMtraversalsbasedoncomplexCSSselectors,weshouldhaveanideaofhowourselectorsareperforming.UnderstandinghowCSSselectorsarematchedagainsttheelementsoftheDOMhelpsuswritemoreefficientselectorswhichperformbetterwhenusedwithjQuery.

ThekeycharacteristicofefficientCSSselectorsisspecificity.Accordingtothis,IDandClassselectorsarealwaysmoreefficientthanselectorswithmanyresultslikedivand*.WhenwritingcomplexCSSselectors,keepinmindthattheyareevaluatedfromtherighttotheleftandthataselectorgetsrejectedafterrecursivelytestingitagainsteveryparentelementuntiltherootoftheDOM.

Asaresult,trytobeasspecificaspossiblewiththerightmostselectorinordertocutdownthematchedelementsasquicklyaspossibleduringtheexecutionoftheselector.

//initiallymatchesalltheanchorsofthepage

//andthenremovesthosethatarenotchildrenofthecontainer

$('.containera');

//performsbetter,sinceitmatchesfewerelements

//inthefirststepoftheselector'sevaluation

$('.container.mySpecialLinks');

TheotherperformancetipisusingtheChildSelector(“parent>child”)whereverapplicable,inanefforttoeliminatetherecursionoverallthehierarchyoftheDOMtree.Agreatexamplewherethiscanbeappliedisincaseswherethetargetelementscanbefoundataspecificdescendantlevelofacommonancestorelement:

//initiallymatchesallthediv'softhepage,whichisbad

$('.containerdiv');

//alotfasterthanthepreviousone,

//sinceitavoidstherecursiveclasschecks

//untilreachingtherootoftheDOMtree

$('.container>div');

//bestofall,butcan'tbeusedalways

$('.container>.specialDivs');

TipThesametipscanalsobeappliedtoCSSselectorsthatareusedforstylingpages.EventhoughbrowsershavebeentryingtooptimizeanygivenCSSselector,thetipsdescribedabovecangreatlyreducethetimethatisrequiredtorenderawebpage.

NoteFormoreinformationonjQueryCSSselectorperformance,youcanvisit:http://learn.jquery.com/performance/optimize-selectors/

Page 317: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 318: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

WritingefficientjQuerycodeLet’snowproceedandanalyzethemostimportantjQuery-specificperformancetips.Formoreinformationaboutthemostup-to-dateperformancetipsonjQuery,keepaneyeontherelevantpageforjQuery’sLearningCenter:http://learn.jquery.com/performance

Page 319: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

MinimizingDOMtraversalsSincejQuerymadeDOMtraversalssosimple,manywebdevelopersoverusedthe$()functioneverywhere,eveninsubsequentlinesofcode,makingtheirimplementationsslowerbyexecutingunnecessarycode.OneofthemainreasonsthatthecomplexityoftheoperationissooftenoverlookedistheelegantandminimalisticsyntaxthatjQueryuses.DespitethefactthatJavaScriptbrowserenginesbecamemanytimesfasterinthelastfewyears,withperformancecomparabletomanycompiledlanguages,theDOMAPIisstilloneoftheirslowestcomponentsand,asaresult,developershavetominimizetheirinteractionswithit.

CachingjQueryobjectsStoringtheresultofthe$()functiontoalocalvariableandsubsequentlyusingittooperateontheretrievedelementsisthesimplestwayofeliminatingunnecessaryexecutionsofthesameDOMtraversals.

var$element=$('.boxHeader');

if($element.css('position')==='static'){

$element.css({position:'relative'});

}

$element.height('40px');

$element.wrapInner('<b>');

Inthepreviouschapters,weevensuggestedstoringCompositeCollectionObjectsofimportantpageelementsaspropertiesofourmodulesandreusingthemeverywhereinourapplication:

dashboard.$container=null;

dashboard.init=function(){

dashboard.$container=$('.dashboardContainer');

};

TipCachingretrievedelementsonmodulesisaverygoodpracticewhentheelementsarenotgoingtoberemovedfromthepage.Keepinmindthat,whendealingwithelementswithshorterlifespans,inordertoavoidmemoryleaks,youhavetoeitherensurethatyouclearalltheirreferenceswhentheyareremovedfromthepageorhaveafreshreferenceretrievedwhenrequiredandcacheitonlyinsideyourfunctions.

ScopingelementtraversalsInsteadofwritingcomplexCSSselectorsforyourtraversalslike:

$('.dashboardContainer.dashboardCategories');

YoucaninsteadhavethesameresultinamoreefficientwaybyusinganalreadyretriedancestorelementtoscopetheDOMtraversal.Thisway,youarenotonlyusingsimplerCSSselectorsthatarefastertomatchagainstpageelements,butyouarealsoreducingthenumberofelementsthathavetobechecked.Moreover,theresultingimplementationshavelesscoderepetitions(areDRYer)andtheCSSselectorsusedaresimpleandasa

Page 320: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

resultmorereadable.

var$container=$('.dashboardContainer');

$container.find('.dashboardCategories');

Additionally,thispracticeworksevenbetterwithmodule-widecachedelementslikethoseweusedinthepreviouschapters:

$boxContainer=dashboard.$container.find('.boxContainer');

ChainingjQuerymethodsOneofthecharacteristicsofalljQueryAPIsisthattheyareFluentinterfaceimplementationsthatenableustochainseveralmethodinvocationsonasingleCompositeCollectionObject.

$('.boxContent').html('')

.append('<ahref="#">')

.height('40px')

.wrapInner('<b>');

Aswediscussedinpreviouschapters,chainingallowsustoreducethenumberofusedvariablesandleadstomorereadableimplementationswithfewercoderepetitions.

Page 321: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

Don’toverdoitKeepinmindthatjQueryalsoprovidesthe$.fn.end()method(http://api.jquery.com/end/)asawayofmovingbackfromachainedtraversal.

$('.box')

.filter(':even')

.find('.boxHeader')

.css('background-color','#0F0')

.end()

.end()//undothefilterandfindtraversals

.filter(':odd')//appliedontheinitial.boxresults

.find('.boxHeader')

.css('background-color','#F00');

Eventhoughthisisahandymethodinmanycases,youshouldavoidoverusingitsinceitcandamagethereadabilityandperformanceofyourcode.Inmanycases,usingcachedelementcollectionsinsteadof$.fn.end()resultsinfasterandmorereadableimplementations.

Page 322: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

ImprovingDOMmanipulationsAswesaidearlier,theextensiveuseoftheDOMAPIisoneofthemostcommonthingsthatmakesanapplicationslower,especiallywhenusedtomanipulatethestateoftheDOMtree.Inthissection,wewillshowcasesometipstoimproveperformancewhenmanipulatingtheDOMtree.

CreatingDOMelementsThemostefficientwaytocreateDOMelementsistoconstructaHTMLstringandappendittotheDOMtreeusingthe$.fn.html()method.Additionally,sincethisistoolimitinginsomeusecases,youcanalsousethe$.fn.append()and$.fn.prepend()methods,whichareslightlyslowerbutmaybeabettermatchforyourimplementation.Ideally,ifmultipleelementsneedtobecreated,youshouldtrytominimizetheinvocationofthesemethodsbycreatingaHTMLstringthatdefinesalltheelementsandtheninsertingitintotheDOMtree,asshownbelow:

varfinalHtml='';

for(vari=0,len=questions.length;i<len;i++){

varquestion=questions[i];

finalHtml+='<div><label><span>'+question.title+':</span>'+

'<inputtype="checkbox"name="'+question.name+'"/>'+

'</label></div>';

}

$('form').html(finalHtml);

Anotherwaytoachievethesameresult,isbyusinganarraytostoretheHTMLforeachintermediateelementandthenjointhemrightbeforetheinsertiontotheDOMtree:

varparts=[];

for(vari=0,len=questions.length;i<len;i++){

varquestion=questions[i];

parts.push('<div><label><span>'+question.title+':</span>'+

'<inputtype="checkbox"name="'+question.name+'"/>'+

'</label></div>');

}

$('form').html(parts.join(''));

NoteThisisacommonlyusedpatternsince,untilrecently,itperformedbetterthanconcatenatingtheintermediateresultswith“+=”.

StylingandanimatingWheneverpossible,useCSSclassesforyourstylingmanipulationsbyutilizingthe$.fn.addClass()and$.fn.removeClass()methodsinsteadofmanuallymanipulatingthestyleoftheelementswiththe$.fn.css()method.That’sespeciallyusefulwhenyouneedtostylealargenumberofelementssincethisisthemainpurposeofCSSclassesandbrowsershavealreadyspentyearsoptimizingit.

Tip

Page 323: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

Asanextraoptimizationsteptominimizethenumberofmanipulatedelements,youcanapplyCSSclassesonasinglecommonancestorelementanduseadescendantCSSselectortoapplyyourstyling,asdemonstratedhere:https://developer.mozilla.org/en-US/docs/Web/CSS/Descendant_selectors

Whenyoustillneedtousethe$.fn.css()method,forexample,whenyourimplementationneedstobeimperative,usetheinvocationoverloadthatacceptsobjectparameters:http://api.jquery.com/css/#css-properties.Inthisway,therequiredmethodinvocationsareminimizedwhenapplyingmultiplestylesonelementsandyourcodeisbetterorganized.

Moreover,avoidmixingmethodsthatmanipulatetheDOMwithmethodsthatreadfromtheDOMsincethiswillforceareflowofthepagesothatthebrowsercancalculatethenewpositionsofthepageelements.

Insteadofdoingsomethinglikethis:

$('h1').css('padding-left','2%');

$('h1').css('padding-right','2%');

$('h1').append('<b>!!</b>');

varh1OuterWidth=$('h1').outerWidth();

$('h1').css('margin-top','5%');

$('body').prepend('<b>--!!--</b>');

varh1Offset=$('h1').offset();

Prefergroupingthenon-conflictingmanipulationstogetherlikethis:

$('h1').css({

'padding-left':'2%',

'padding-right':'2%',

'margin-top':'5%'

}).append('<b>!!</b>');

$('body').prepend('<b>--!!--</b>');

varh1OuterWidth=$('h1').outerWidth();

varh1Offset=$('h1').offset();

Thebrowsercanthusskipsomere-renderingsofthepage,resultinginfewerpausesoftheexecutionofyourcode.

NoteFormoreinformationaboutreflows,visitthefollowingpage:https://developers.google.com/speed/articles/reflow

Lastly,notethatalljQuery-generatedanimationsinv1.xandv2.xareimplementedusingthesetTimeout()function.Thisisgoingtochangeinv3.xofjQuerywhichplanstousetherequestAnimationFrame()function,whichisabettermatchforcreatingimperativeanimations.Untilthen,youcanusethejQuery-requestAnimationFrameplugin(https://github.com/gnarf/jquery-requestAnimationFrame)whichmonkey-patchesjQuerytousetherequestAnimationFrame()functionforitsanimationswhenitisavailable.

Page 324: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

ManipulatingdetachedelementsAnotherwaytoavoidunnecessaryrepaintsofthepagewhilemanipulatingDOMelementsistodetachtheelementfromthepageandre-attachitaftercompletingyourmanipulations.Workingwithadetachedin-memoryelementismuchfasteranddoesnotcausereflowsonthepage.

Inordertoachievethat,weusethe$.fn.detach()methodwhich,incontrastto$.fn.remove(),preservesalleventhandlersandjQuerydataonthedetachedelement.

var$h1=$('#pageHeader');

var$h1Cont=$h1.parent();

$h1.detach();

$h1.css({

'padding-left':'2%',

'padding-right':'2%',

'margin-top':'5%'

}).append('<b>!!</b>');

$h1Cont.append($h1);

Additionally,tobeabletoplacethemanipulatedelementbackintoitsoriginalposition,wecancreateandinsertahiddenplaceholderelementintotheDOM.Thisemptyandhiddenelementdoesnotaffecttherenderingofthepageandisremovedaftertheoriginalitemisplacedbackintoitsoriginalposition.

var$h1PlaceHolder=$('<divstyle="display:none;"></div>');

var$h1=$('#pageHeader');

$h1PlaceHolder.insertAfter($h1);

$h1.detach();

$h1.css({

'padding-left':'2%',

'padding-right':'2%',

'margin-top':'5%'

}).append('<b>!!</b>');

$h1.insertAfter($h1PlaceHolder);

$h1PlaceHolder.remove();

$h1PlaceHolder=null;

NoteFormoreinformationaboutthe$.fn.detach()method,youcanreadthedocumentationat:http://api.jquery.com/detach/

IntroducingtheFlyweightPatternAccordingtoComputerScience,aFlyweightisanobjectthatisusedasameansofreducingthememoryconsumptionofanimplementationbyprovidingfunctionalityand/ordatathataresharedwithotherobjectinstances.ThePrototypesofJavaScriptconstructorfunctionscanbecharacterizedasFlyweightssinceeveryobjectinstancecanuseallofthe

Page 325: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

methodsandpropertiesthataredefinedinitsprototypeuntilitoverwritesthem.Ontheotherhand,classicalFlyweightsareseparateobjectsfromtheobjectfamilythattheyareusedwithandoftenholdtheshareddataandfunctionalityinspecialdatastructures.

Page 326: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

UsingDelegateObserversAgreatexampleofFlyweightsinjQueryapplicationsisDelegateObserverswhich,aswesawintheDashboardexampleinChapter2,TheObserverPattern,cangreatlyreducethememorydemandsofanimplementationbyworkingasacentralizedeventhandlerforalargegroupofelements.Inthisway,wecanavoidthecostofsettingupseparateobserversandeventhandlersforeveryelementandusethebrowser’seventbubblingmechanismtoobserveforthemonasinglecommonancestorelementandfiltertheirorigin.

$boxContainer.on('click','.boxCloseButton',function(){

var$button=$(this);

dashboard.informationBox.close($button);

});

NoteTheactualFlyweightobjectistheeventhandleralongwiththecallbackthatisattachedtotheancestorelement.

Page 327: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

Using$.noop()ThejQuerylibraryoffersthe$.noop()methodwhichisactuallyanemptyfunctionthatcanbesharedamongimplementations.Usingemptyfunctionsasdefaultcallbackvaluessimplifiesandimprovesthereadabilityofanimplementationbyreducingthenumberofifstatements.ThisishandyforjQuerypluginsthatalreadyencapsulatecomplexfunctionality.

functiondoLater(callbackFn){

setTimeout(function(){

if(callbackFn){

callbackFn();

}

},500);

}

//with$.noop()

functiondoLater(callbackFn){

callbackFn=callbackFn||$.noop();

setTimeout(function(){

callbackFn();

},500);

}

Insuchsituations,wheretheimplementationrequirementsorthepersonaltasteofthedeveloperhasledtousingemptyfunctions,the$.noop()methodisusefulasawaytolowermemoryconsumptionbysharingasingleemptyfunctioninstanceamongallthedifferentpartsofanimplementation.Anaddedbenefitofusingthe$.noop()methodforeverypartofanimplementationisthatwecanalsocheckwhetherapassedfunctionreferenceistheemptyfunctionbysimplycheckingcallbackFn===$.noop().

NoteFormoreinformation,youcanfindthedocumentationat:http://api.jquery.com/jQuery.noop/

Page 328: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

Usingthe$.singlepluginAnothersimpleexampleoftheFlyweightpatterninjQueryapplicationsisthejQuery.singlepluginasdescribedbyJamesPadolseyinhisarticle,76bytesforfasterjQuery,whichtriestoeliminatethecreationofnewjQueryobjectswheneverweneedtoapplyjQuerymethodsonasinglepageelement.TheimplementationisquitesmallandcreatesasinglejQuerycompositecollectionobjectthatisreturnedoneveryinvocationofthejQuery.single()method,containingthepageelementthatwasusedasanargument.

jQuery.single=(function(){

varcollection=jQuery([1]);

//Fillwith1item,tomakesurelength===1

returnfunction(element){

collection[0]=element;//Givecollectiontheelement:

returncollection;//Returnthecollection:

};

}());

ThejQuery.singlepluginisusefulwhenusedinobserverslike$.fn.on()anditerationswithmethodslike$.each().

$boxContainer.on('click','.boxCloseButton',function(){

//var$button=$(this);

var$button=$.single(this);

//thisisnotcreatinganynewobject

dashboard.informationBox.close($button);

});

ThebenefitsofusingthejQuery.singleplugincomefromthefactthatwearecreatingfewerobjectsand,asaresult,thebrowser’sGarbageCollectorwillalsohavelessworktodowhenfreeingupthememoryofshortlivedobjects.

Asasidenote,keepinmindthesideeffectsofhavingasinglejQueryobjectreturnedbyeveryinvocationofthe$.single()methodandthefactthatthelastinvocationargumentwillbestoreduntilthenextinvocationofthemethod:

varbuttons=document.getElementsByTagName('button');

var$btn0=$.single(buttons[0]);

var$btn1=$.single(buttons[1]);

$btn0===$btn1//thisistrue

Additionally,incasethatyouusesomethinglike$btn1.remove()thentheelementwillnotbefreeduntilthenextinvocationofthe$.single()methodwhichwillremoveitfromtheplugin’sinternalcollectionobject.

AnothersimilarbutmoreextensivepluginisthejQuery.flypluginwhichcanbeinvokedwitharraysandjQueryobjectsasparameters.

NoteFormoreinformationaboutjQuery.singleandjQuery.fly,youcanvisitthefollowingURLs:http://james.padolsey.com/javascript/76-bytes-for-faster-jquery/andhttps://github.com/matjaz/jquery.fly.

Page 329: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

Ontheotherhand,thejQueryimplementationthathandlestheinvocationofthe$()methodwithasinglepageelementisnotcomplexatallandonlycreatesasinglesimpleobject.

jQuery=function(selector,context){

returnnewjQuery.fn.init(selector,context);

};

/*...*/init=jQuery.fn.init=function(selector,context,root){

/*...else*/

if(selector.nodeType){

this.context=this[0]=selector;

this.length=1;

returnthis;

}/*...*/

};

Moreover,theJavaScriptenginesofmodernbrowsershavealreadybecomequiteefficientwhendealingwithshort-livedobjectssincesuchobjectsarecommonlypassedaroundanapplicationasmethodinvocationparameters.

Page 330: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 331: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

LazyLoadingModulesFinally,wewillgetanintroductiontotheadvancedtechniqueofLazyLoadingModules.Thekeyconceptofthispracticeisthat,duringthepageload,thebrowserwillonlydownloadandexecutethosemodulesthatarerequiredfortheinitialrenderingofthepagewhiletherestoftheapplicationmodulesarerequestedafterthepageisfullyloadedandisrequiredtorespondtoauseraction.RequireJS(http://requirejs.org/)isapopularJavaScriptlibrarythatisusedasamoduleloaderbut,forsimplecases,wecanachievethesameresultwithjQuery.

Asanexampleofthis,wewilluseittolazyloadtheinformationBoxmoduleoftheDashboardexamplethatwesawinpreviouschapters,afterthefirstclickoftheuserontheDashboard’s<button>.WewillabstracttheimplementationthatisresponsiblefordownloadingandexecutingJavaScriptfilesintoagenericandreusablemodulenamedmoduleUtils:

(function(){

'usestrict';

dashboard.moduleUtils=dashboard.moduleUtils||{};

dashboard.moduleUtils.getModule=function(namespaceString){

varparts=namespaceString.split('.');

varresult=parts.reduce(function(crnt,next){

returncrnt&&crnt[next];

},window);

returnresult;

};

varongoingModuleRequests={};

dashboard.moduleUtils.ensureLoaded=function(namespaceString){

varexistingNamespace=this.getModule(namespaceString);

if(existingNamespace){

return$.Deferred().resolve(existingNamespace);

}

if(ongoingModuleRequests[namespaceString]){

returnongoingModuleRequests[namespaceString];

}

varmodulePromise=$.getScript(namespaceString.toLowerCase()+

'.js')

.always(function(){

ongoingModuleRequests[namespaceString]=null;

}).then(function(){

returndashboard.moduleUtils.getModule(namespaceString);

});

ongoingModuleRequests[namespaceString]=modulePromise;

returnmodulePromise;

};

Page 332: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

})();

ThegetModule()methodacceptsthemodule’snamespaceasastringparameterandreturnseithertheModule’sSingletonObjectitselforafalsyvalueifthemoduleisnotalreadyloaded.ThisisdonewiththeArray.reduce()methodwhichisusedtoiterateoverthedifferentpartsofthenamespacestring,usingthedot(.)asadelimiterandevaluatingeachpartonthepreviousobjectcontext,startingwithwindow.

NoteFormoreinformationabouttheArray.reduce()method,youcanvisit:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce

ensureLoaded()istheprimarymethodofthemoduleUtilsmoduleandisresponsibleforretrievingandexecutingmodulesthatarenotalreadyloaded.ItfirstusesthegetModule()methodtocheckwhethertherequestedmodulehasalreadybeenloadedand,ifso,returnsitsnamespaceobjectasaResolvedPromise.

Thenextstep,ifamodulehasnotyetbeenloaded,istochecktheongoingModuleRequestsobjecttoverifywhethertherequestedmoduleisnotalreadybeingdownloaded.Inordertodothat,theongoingModuleRequestsobjectusesthemodule’snamespacestringasapropertyandstoresthePromisesoftheAJAXrequeststhatareusedtoretrievethe.jsfilesfromtheserver.IfaPromiseobjectisavailablethenwecaninferthattheAJAXrequestisstillongoingand,insteadofstartinganewone,wereturntheexistingPromise.

Finally,whennoneoftheabovereturnsaresult,weusethelowercasemodulefilenamingconventionthatwediscussedinpreviouschaptersandusejQuery’s$.getScript()methodtoinitiateanAJAXrequesttoretrievetherequestedmodulefile.ThePromisecreatedfortheAJAXrequestisassignedastotheappropriatepropertyoftheongoingModuleRequestsobjectandisthenreturnedtothecallerofthemethod.When,atalaterpointintime,thePromiseisFulfilled,were-evaluatethemoduleandreturnitasthefinalresultofthereturnedPromise.Moreover,regardlessoftheresultoftheAJAXrequest,thePromiseisalsoremovedfromtheongoingModuleRequestsobjectinordertokeeptheimplementationreusableincaseofanetworkfailureandalsofreeupthememorythatwasallocatedfortherequest.

NoteKeepinmindthatthe$.getScript()methodmightnotworkinsomebrowserswhenthepageisloadedthroughthefilesystem,butdoesworkasintendedwhenservedusingawebserverlikeApache,IISornginx.Formoreinformationabout$.getScript(),youcanvisit:http://api.jquery.com/jQuery.getScript/

TheonlychangethatweintroducedtotheexistingimplementationoftheinformationBoxmoduleforthisdemonstrationwastomakeitself-initializableinanattempttoreducethecomplexityoftheensureLoaded()method.

(function(){

Page 333: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

'usestrict';

dashboard.informationBox=dashboard.informationBox||{};

var$boxContainer=null;

dashboard.informationBox.init=function(){/*…*/};

$(document).ready(dashboard.informationBox.init);

/*...*/

})();

Finally,wealsohadtochangetheimplementationofthecategoriesmodulesothatitwouldusetheensureLoaded()methodbeforeusingtheinformationBoxmodule.Asyoucanseebelow,wehadtorefactorthecodehandlingtheclickeventonthedashboard’s<button>sincetheensureLoaded()methodreturnsaPromiseasaresult:

//indashboard.categories.init

dashboard.$container.find('.dashboardCategories').on('click','button',

function(){

var$button=$(this);

varitemName=$button.text();

varp=dashboard.moduleUtils.ensureLoaded('dashboard.informationBox');

p.then(function(){

dashboard.informationBox.openNew(itemName);

});

});

Page 334: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface
Page 335: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

SummaryInthischapter,welearnedseveraloptimizationtechniquesthatcanbeusedtoimprovetheperformanceofjQueryapplications,especiallywhentheybecomelargeandcomplex.

WestartedwithsimplepracticeslikebundlingandminifyingourJavaScriptfilesanddiscussedthebenefitsofusingCDNstoloadthird-partylibraries.WethenwentontoanalyzesomesimplepatternstowritingefficientJavaScriptcodeandlearnedhowtowriteefficientCSSselectorstoimprovethepage’srenderingspeedandDOMtraversalsusingjQuery.

WecontinuedwithjQuery-specificpracticessuchascachingofjQueryCompositeCollectionObjects,howtominimizeDOMmanipulations,andhadareminderoftheDelegateObserverpattern,asagoodexampleoftheFlyweightPattern.Lastly,wegotanintroductiontotheadvancedtechniqueofLazyLoadingandsawademonstrationofhowtoloadthevariousmodulesofanimplementationprogressively,basedonuseractions.

Aftercompletingthischapter,wearenowabletoapplythemostcommonoptimizationpatternstoourimplementationsandusethischapterasachecklistofbestpracticesandperformancetipsbeforemovinganapplicationtoaproductionenvironment.

Page 336: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

IndexA

$.ajax()method/AcceptingconfigurationparametersaddEventListener()methods

URL/IntroducingtheObserverPatternapplications

developing,withCompositePattern/UsingtheCompositePatterntodevelopapplicationsUnderscore.jstemplates,using/UsingUnderscore.jstemplatesinourapplicationsHandlebars.jstemplates,using/UsingHandlebars.jsinourapplications

Array.reduce()methodreference/LazyLoadingModules

attachEvent()methodURL/IntroducingtheObserverPattern

AustralianNationalUniversity(ANU)/Writingmethodsthatacceptcallbacks

Page 337: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

BBabeltranspiler

URL/IntroducingES6Modulesbroker/IntroducingthePublish/SubscribePatternBuilderPattern

about/IntroducingtheBuilderPatternadopting,byjQuery/HowitisadoptedbyjQuery’sAPIusing,byjQueryinternally/HowitisusedbyjQueryinternallyusing,inapplications/Howtouseitinourapplications

Page 338: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

CCallbackHell

URL/AvoidingtheCallbackHellanti-patterncallbacks

about/Programmingwithcallbacksprogrammingwith/Programmingwithcallbackssimplecallbacks,usinginJavaScript/UsingsimplecallbacksinJavaScriptsetting,asobjectproperties/Settingcallbacksasobjectpropertiesusing,injQueryapplications/UsingcallbacksinjQueryapplicationsmethods,writing/Writingmethodsthatacceptcallbacks

callbacks,orchestratingabout/Orchestratingcallbacksqueuing,inorderexecution/QueuinginorderexecutionCallbackHellanti-pattern,avoiding/AvoidingtheCallbackHellanti-patternrunningconcurrently/Runningconcurrently

categoriesmodule/ThecategoriesmoduleCDNs

about/UsingCDNsusing/UsingCDNsJSDelivrAPI,using/UsingJSDelivrAPI

closureabout/IntroducingtheObserverPatternURL/IntroducingtheObserverPattern

ClosureCompilerreference/Bundlingandminifyingresources

closuresURL/TheIIFEbuildingblock

commonJavaScriptcodeoptimizing/OptimizingcommonJavaScriptcodeforloops,writingfor/Writingbetterforloops

CompositePatternabout/TheCompositePatternusing,byjQuery/HowtheCompositePatternisusedbyjQuerycomparing,withplainDOMAPIbenefits/ComparingthebenefitsovertheplainDOMAPIused,fordevelopingapplications/UsingtheCompositePatterntodevelopapplicationssampleusecase/AsampleusecaseCollectionImplementation/TheCompositeCollectionImplementationexampleexecution/Anexampleexecutionalternativeimplementations/Alternativeimplementationspairing,withIteratorPattern/HowitpairswiththeCompositePattern

configurationparameters

Page 339: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

accepting/AcceptingconfigurationparametersContentDeliveryNetwork(CDN)/UsingCDNscountermodule/ThecountermoduleCSSSelectors/ThejQueryDOMTraversalAPIcustomeventnamespacing

using/UsingcustomeventnamespacingURL/Usingcustomeventnamespacing

customeventsinjQuery/CustomeventsinjQueryused,forimplementingPublish/SubscribePattern/ImplementingaPub/Subschemeusingcustomevents

Page 340: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

DDashboardapplication

reusableplugins,using/UsingourplugininourDashboardapplicationdashboardexample

Publish/SubscribePattern,using/UsingPub/Subonthedashboardexampledashboardmodule/Themaindashboardmoduledeferredobserver/Thecategoriesmoduledeferredobservers/ThecountermoduleDelegatedEventObserverPattern

about/IntroducingtheDelegatedEventObserverPatternused,forsimplifyingcode/Howitsimplifiesourcodememoryusagebenefits,comparing/Comparethememoryusagebenefits

DelegateObserversusing/UsingDelegateObservers

descendantCSSselectorreference/Stylingandanimating

DocumentFragmentabout/HowitisadoptedbyjQuery’sAPI

DocumentFragmentsreference/HowitisadoptedbyjQuery’sAPI

DocumentObjectMode(DOM)URL/jQueryandDOMscriptingmanipulating,withjQuery/ManipulatingtheDOMusingjQuery

DOMAPI/ThejQueryDOMTraversalAPIDOMLevel2Eventspecification

URL/HowitiscomparedwitheventattributesDOMmanipulations,improving

about/ImprovingDOMmanipulationsDOMelements,creating/CreatingDOMelementsanimating/Stylingandanimatingstyling/Stylingandanimatingdetachedelements,manipulating/ManipulatingdetachedelementsFlyweightPattern/IntroducingtheFlyweightPattern

DOMscriptingandjQuery/jQueryandDOMscripting

DOMtraversals,minimizingabout/MinimizingDOMtraversalsjQueryobjects,caching/CachingjQueryobjectselementtraversals,scoping/ScopingelementtraversalsjQuerymethods,chaining/ChainingjQuerymethods

Page 341: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

E$.extend()helpermethod

URL/AcceptingconfigurationparametersefficientjQuerycode

writing/WritingefficientjQuerycodeDOMtraversals,minimizing/MinimizingDOMtraversalsoveruse,avoiding/Don’toverdoitDOMmanipulations,improving/ImprovingDOMmanipulationsDelegateObservers,using/UsingDelegateObservers$.noop(),using/Using$.noop()$.singleplugin,using/Usingthe$.singleplugin

EncapsulationURL/Encapsulatinginternalpartsofanimplementation

ES5StrictModeusing/UsingES5StrictMode

ES6modulesabout/IntroducingES6ModulesURL/IntroducingES6Modules

eventattributesURL/Howitiscomparedwitheventattributes

eventlistenersremoving,URL/Avoidmemoryleaks

eventobjectURL/Extendingtheimplementation

Page 342: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

F$.fn.addClass()method/WorkingonCompositeCollectionObjects$.fn.closest()method

URL/Demonstrateasampleusecase$.fn.data()method/ImplementingastatefuljQueryPlugin$.fn.end()method

reference/Don’toverdoit$.fn.ready()method/Thedocument-readyobserver

URL/Thedocument-readyobserverFacadePattern

about/IntroducingtheFacadePatternbenefits/Thebenefitsofthispatternadopting,byjQuery/HowitisadoptedbyjQuery

Facadesusing,inapplications/UsingFacadesinourapplications

Factoriesusing,inapplications/UsingFactoriesinourapplications

FactoryPatternabout/IntroducingtheFactoryPatternkeyconcept/IntroducingtheFactoryPatternadopting,byjQuery/HowitisadoptedbyjQuery

falsyJavaScriptvaluereference/Writingbetterforloops

FlyweightPatternabout/IntroducingtheFlyweightPattern

functionData()URL/ThejQueryonmethod

Page 343: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

G$.getScript()method

URL/RetrievingHTMLtemplatesasynchronouslyreference/LazyLoadingModules

genericiteratorfunction/HowtheIteratorPatternisusedbyjQuerygettermethod

implementing/ImplementinggetterandsettermethodsgetValuesmethod/TheCompositeCollectionImplementationglobalnamespace/AvoidingglobalvariableswithNamespaces,TheRevealingModulePatternGoogle’sJavaScriptStyleGuide

URL/Thewideacceptancegrunt-contrib-concatproject

URL/UsingModulesinjQueryapplications

Page 344: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

HHandlebars.js

about/IntroducingHandlebars.jsURL/IntroducingHandlebars.js,UsingHandlebars.jsinourapplications,Pre-compilingtemplatesusing,inapplications/UsingHandlebars.jsinourapplicationstemplatepre-compilation,URL/Pre-compilingtemplates

HTMLtemplatesseparating,fromJavaScriptcode/SeparatingHTMLtemplatesfromJavaScriptcode,SeparatingHTMLtemplatesfromJavaScriptcoderetrievingasynchronously/RetrievingHTMLtemplatesasynchronouslyadopting,inexistingimplementation/Adoptingitinanexistingimplementationmoderation/Moderationisbestinallthings

Page 345: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

IIIFE

used,forwrappingjQueryPlugin/WrappingwithanIIFEabout/WrappingwithanIIFE

IIFE-containedmodulevariant/TheIIFE-containedModulevariantIIFEparameters

using/UsingIIFEparametersImmediatelyInvokedFunctionExpression(IIFE)/Thedocument-readyobserver

about/TheIIFEbuildingblockURL/TheIIFEbuildingblock

incrementmethod/TheCompositeCollectionImplementationIndexedDB

URL/RunningconcurrentlyinformationBoxmodule/TheinformationBoxmoduleIteratorPattern

about/TheIteratorPatternusing,byjQuery/HowtheIteratorPatternisusedbyjQuerypairing,withCompositePattern/HowitpairswiththeCompositePatternusing/Wherecanitbeused

Page 346: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

JJavaScript

Prototype-basedprogrammingmodel,URL/TheCompositeCollectionImplementation

JavaScriptcodeHTMLtemplates,separating/SeparatingHTMLtemplatesfromJavaScriptcode,SeparatingHTMLtemplatesfromJavaScriptcode

JavaScriptlibrariesURL/Choosinganame

jQueryandDOMscripting/jQueryandDOMscriptingURL/jQueryandDOMscripting,ManipulatingtheDOMusingjQuery,HowtheIteratorPatternisusedbyjQueryused,formanipulatingDOM/ManipulatingtheDOMusingjQueryMethodChaining/MethodChainingandFluentInterfacesFluentInterfaces/MethodChainingandFluentInterfacesCompositePattern,using/HowtheCompositePatternisusedbyjQueryGitHubpage,URL/HowtheCompositePatternisusedbyjQueryIteratorPattern,using/HowtheIteratorPatternisusedbyjQueryObserverPattern,using/HowitisusedbyjQueryPublish/SubscribePattern/HowitisadoptedbyjQuerycustomevents/CustomeventsinjQuerycodeorganization,URL/Overviewoftheimplementation

jQuery-requestAnimationFramepluginreference/Stylingandanimating

jQuery-UIWidgetFactoryURL/Addingmethodstoyourplugin

jQuery.ajaxSetup()method/AcceptingconfigurationparametersjQuery.guid/ThejQueryonmethodjQuery.noConflict()method

URL/Workingwith$.noConflict()jQueryapplications

modules,using/UsingModulesinjQueryapplicationsMockObjectPattern,using/UsingMockObjectsinjQueryapplications

jQueryequivalentmethodURL/Avoidmemoryleaks

jQueryimplementationabout/HowitisadoptedbyjQueryjQueryDOMTraversalAPI/ThejQueryDOMTraversalAPIpropertyaccessandmanipulationAPI/ThepropertyaccessandmanipulationAPI

jQueryJavaScriptStyleGuideURL/Thewideacceptance

Page 347: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

jQueryonmethod/ThejQueryonmethodjQueryPlugin

about/IntroducingjQueryPluginsprinciples,following/FollowingjQueryprinciplescharacteristics/FollowingjQueryprinciples$.noConflict(),workingwith/Workingwith$.noConflict()wrapping,withIIFE/WrappingwithanIIFEnamingconventions/Choosinganame

jQueryPluginBoilerplateURL/UsingthejQueryPluginBoilerplateusing/UsingthejQueryPluginBoilerplatemethods,adding/Addingmethodstoyourplugin

jQueryPluginRegistryURL/Choosinganame

jQueryprinciplesfollowing/FollowingjQueryprinciplesCompositeCollectionObjects,workingon/WorkingonCompositeCollectionObjectsfurtherchaining/Allowingfurtherchaining

jQueryPromisestransforming,to/TransformingtojQueryPromises

jQuerysourceviewerURL/ThejQueryonmethod

jQuerySourceViewerURL/HowtheCompositePatternisusedbyjQuery

jQueryv3.0A+Promisesimplementationreference/ComparingjQueryandA+Promises

JSDelivrAPIusing/UsingJSDelivrAPIreference/UsingJSDelivrAPI

Page 348: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

LLazyLoadingModules

about/LazyLoadingModulesLevel2SelectorAPI/ThejQueryDOMTraversalAPI

Page 349: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

Mmemoryusagebenefits

comparing/ComparethememoryusagebenefitsMethodChaining/MethodChainingandFluentInterfacesMockjaxjQueryPluginlibrary

reference/ImplementingaMockServiceusing/ImplementingaMockService

MockObjectPatternabout/IntroducingtheMockObjectPatternusing,injQueryapplications/UsingMockObjectsinjQueryapplicationsactualservicerequirements,defining/DefiningtheactualservicerequirementsMockService,implementing/ImplementingaMockServiceMockService,using/UsingtheMockService

ModulePatternabout/TheModulePatternImmediatelyInvokedFunctionExpression(IIFE)buildingblock/TheIIFEbuildingblocksimpleIIFEModulePattern/ThesimpleIIFEModulePatternusing,injQuery/HowitisusedbyjQuerynamespaceparametermodulevariant/TheNamespaceParameterModulevariantIIFE-containedmodulevariant/TheIIFE-containedModulevariant

modulesabout/ModulesandNamespaces,Encapsulatinginternalpartsofanimplementationinternalpartimplementation,encapsulating/Encapsulatinginternalpartsofanimplementationacceptance/Thewideacceptanceusing,injQueryapplications/UsingModulesinjQueryapplications

modules,jQueryapplicationsusing/UsingModulesinjQueryapplicationsdashboardmodule/Themaindashboardmodulecategoriesmodule/ThecategoriesmoduleinformationBoxmodule/TheinformationBoxmodulecountermodule/Thecountermoduleimplementation,overview/Overviewoftheimplementation

MustacheURL/IntroducingHandlebars.js

MutationObserverURL/ImplementingastatefuljQueryPlugin

Page 350: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

N$.noConflict()

working/Workingwith$.noConflict()$.noop()

using/Using$.noop()reference/Using$.noop()

namespacedeventsURL/Usingcustomeventnamespacing

namespaceparametermodulevariant/TheNamespaceParameterModulevariantnamespaces

about/ModulesandNamespaces,AvoidingglobalvariableswithNamespacesinternalpartimplementation,encapsulating/Encapsulatinginternalpartsofanimplementationglobalvariables,avoiding/AvoidingglobalvariableswithNamespacesbenefits/Thebenefitsofthesepatternsacceptance/Thewideacceptance

namespacing/AvoidingglobalvariableswithNamespacesnamingconventions,jQueryPlugin

selecting/ChoosinganameNPM

URL/Choosinganame

Page 351: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

Oobject-orientedJavaScript

URL/ThewideacceptanceObjectLiteral/HowitisadoptedbyjQueryObjectLiteralPattern/TheObjectLiteralPattern,ThesimpleIIFEModulePattern,TheRevealingModulePatternObserverPattern

about/IntroducingtheObserverPatternURL/IntroducingtheObserverPatternusing,injQuery/HowitisusedbyjQueryjQuery.fn.on()method/ThejQueryonmethoddocument-readyobserver/Thedocument-readyobserversampleusecase,demonstrating/Demonstrateasampleusecasecomparing,witheventattributes/Howitiscomparedwitheventattributeseventattributes,comparingwith/Howitiscomparedwitheventattributesmemoryleaks,avoiding/AvoidmemoryleaksandPublish/SubscribePattern,differentiatingbetween/HowitdiffersfromtheObserverPattern

Page 352: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

Ppatterns

benefits/ThebenefitsofthesepatternsperformancetipsonjQuery

reference/WritingefficientjQuerycodeperformantCSSselectors

writing/WritingperformantCSSselectorsplaceholdernotations,_.tempate()method

<%=%>notation/IntroducingUnderscore.js<%-%>/IntroducingUnderscore.js<%%>notation/IntroducingUnderscore.js

Promisesabout/IntroducingtheconceptofPromisesusing/UsingPromisesjQueryPromiseAPI,using/UsingthejQueryPromiseAPIadvancedconcepts/Advancedconceptsjoining/JoiningPromisesusing,byjQuery/HowjQueryusesPromisestransforming,toothertypes/TransformingPromisestoothertypesbenefits/SummarizingthebenefitsofPromises

Promises,chainingabout/ChainingPromisesthrownerrors,handling/Handlingthrownerrors

Promises/A+using/UsingPromises/A+reference/UsingPromises/A+comparing,withjQuery/ComparingjQueryandA+Promisestransforming,to/TransformingtoPromises/A+

Publish/SubscribePatternabout/IntroducingthePublish/SubscribePatternandObserverPattern,differentiatingbetween/HowitdiffersfromtheObserverPatternusing,byjQuery/HowitisadoptedbyjQueryimplementing,withcustomevents/ImplementingaPub/Subschemeusingcustomeventssampleusecase/Demonstratingasampleusecaseusing,ondashboardexample/UsingPub/Subonthedashboardexampleimplementation,extending/Extendingtheimplementation

publishers/IntroducingthePublish/SubscribePattern

Page 353: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

RRequireJS

URL/LazyLoadingModulesresources

bundling/Bundlingandminifyingresourcesminifying/Bundlingandminifyingresources

reusablepluginscreating/Creatingreusablepluginsconfigurationparameters,accepting/AcceptingconfigurationparametersstatefuljQueryPlugins,writing/WritingstatefuljQuerypluginsstatefuljQueryPlugin,implementing/ImplementingastatefuljQueryPlugininstance,destroying/Destroyingaplugininstancegettermethod,implementing/Implementinggetterandsettermethodssettermethods,implementing/Implementinggetterandsettermethodsusing,inDashboardapplication/UsingourplugininourDashboardapplication

RevealingModulePatternabout/TheRevealingModulePattern

Page 354: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

S$.singleplugin

using/Usingthe$.singleplugin<script>tag/Placingscriptsneartheendofthepagesampleusecase,ObserverPattern

demonstrating/Demonstrateasampleusecasesampleusecase,Publish/SubscribePattern

demonstrating/Demonstratingasampleusecaseobject,usingasbroker/Usinganyobjectasabroker

scriptsplacing,nearendofpage/Placingscriptsneartheendofthepage

SeparationofConcernsabout/EncapsulatinginternalpartsofanimplementationURL/Encapsulatinginternalpartsofanimplementation

SeparationofConcernsprinciple/Thebenefitsofthispatternsettermethod

implementing/Implementinggetterandsettermethodssimplecallback

defining/IntroducingtheObserverPatternsimpleIIFEModulePattern

about/ThesimpleIIFEModulePatternSingleResponsibilityprinciple

URL/TheIteratorPatternSizzle/ThejQueryDOMTraversalAPI,WritingperformantCSSselectors

URL/HowitisusedbyjQueryreference/ThejQueryDOMTraversalAPI

specifiedNodeTypesURL/HowtheCompositePatternisusedbyjQuery

statefuljQueryPluginswriting/WritingstatefuljQuerypluginsimplementing/ImplementingastatefuljQueryPlugininstance,destroying/Destroyingaplugininstance

strictexecutionmodeURL/WrappingwithanIIFE

strictmode,JavaScriptURL/UsingES5StrictMode

subscribers/IntroducingthePublish/SubscribePattern

Page 355: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

TTiny

URL/ImplementingaPub/SubschemeusingcustomeventstruthyJavaScriptvalue

reference/Writingbetterforloops

Page 356: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

UUglifyJS

reference/BundlingandminifyingresourcesUnderscore.js

about/IntroducingUnderscore.jsusing,inapplications/UsingUnderscore.jstemplatesinourapplicationsHTMLtemplates,separatingfromJavaScriptcode/SeparatingHTMLtemplatesfromJavaScriptcode,SeparatingHTMLtemplatesfromJavaScriptcodetemplates,pre-compiling/Pre-compilingtemplates

Page 357: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

Vvariable

namingconventions/ManipulatingtheDOMusingjQuery

Page 358: jQuery Design Patterns · 2016. 5. 12. · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount offers, and more Why subscribe? Preface

YYUICompressor

reference/Bundlingandminifyingresources