porting flickr to yui3 - f2e summit
DESCRIPTION
TRANSCRIPT
Porting Flickr to YUI 3Ross Harmes
Porting Flickr to YUI 3Lessons in Performance
Ross Harmes
In August we launched a new photo page…
We decided to completely demolish the old page and rebuild with YUI3
Using YUI3 was a delight…
…but blindly converting from 2 to 3 could lead to some problems
The easy part: converting from YUI2 to 3
The big secret: it's really easy, and mostly mechanical
Events work in mostly the same way
DOM calls are now made off of nodes instead of Y.DOM
Events and DOM interactions are probably 90% of the code for most sites
We found that there were two ways to do it
1. Convert just enough to make it work in YUI3
2. Rewrite it using YUI3 idioms
We used both techniques
The bottom line: give it a try
The harder part: making your converted code fast
1. Action queuing
One of the first perf. recommendations is to move all the JS to the bottom of the page
This means UI elements that need JS to work will fallback to the non-JS case until the scripts load
Our solution: Action Queuing
This isn't making the JS load faster
Getting creative with the loading indicators helps
2. Combo handler
We use a lot of small JS modules on the page. This made our combo URLs very long:http://l.yimg.com/g/combo.gne?event/event-min.js&j/query-string-args.js.v85201.14&j/flickr_location_search.js.v85793.14&j/
flickr_nav.js.v92497.14&base/base-min.js&anim/anim-min.js&dump/dump-min.js&datatype/datatype-xml-min.js&substitute/substitute-min.js&queue-promote/queue-promote-min.js&io/io-min.js&json/json-min.js&j/flickr_api.js.v93039.14&j/history-manager.js.v90829.14&j/photo-data.js.v92868.14&j/context-data.js.v92557.14&j/context-manager.js.v91220.14&j/sprintf.js.v90343.14&j/transjax-base.js.v85036.14&j/focus-tracker.js.v93044.14&event-simulate/event-simulate-min.js&j/photo-button-bar-transjax-en-us.js.v92588.14&j/image-fader.js.v85225.14&j/number-transjax-en-us.js.v90582.14&j/number.js.v87306.14&j/photo-filmstrip-transjax-en-us.js.v90793.14&j/photo-filmstrip.js.v92881.14&event/event-synthetic-min.js&j/event-annotations.js.v91160.14&j/event-mousedrag.js.v90789.14&j/math.js.v87441.14&j/fave-star.js.v91965.14&j/global-dialog-transjax-en-us.js.v85507.14&j/global-dialog-zeus.js.v92830.14&j/keyboard-shortcut-manager.js.v92698.14&node/node-event-simulate-min.js&j/photo-permalink.js.v91170.14&j/yahoo/autocomplete_2.5.1-zeus.js.v92829.14&j/bo-selecta-transjax-en-us.js.v90792.14&j/bo-selecta-zeus.js.v91866.14&cookie/cookie-min.js&j/dejaview-zeus.js.v90642.14&j/photo-people-transjax-en-us.js.v90822.14&j/photo-people-controller.js.v88235.14&j/input-hint.js.v86479.14&j/photo-comments-transjax-en-us.js.v92483.14&j/swfobject.js.v85491.14&j/photo-comments.js.v92853.14&j/photo-keyboard-shortcuts.js.v92892.14&j/box-host.js.v89305.14&j/photo-notes-transjax-en-us.js.v93010.14&j/string-filters.js.v91087.14&j/photo-notes-zeus.js.v93044.14&j/excanvas.js.v39120.14&j/bitmap-text-zeus.js.v87486.14&j/bitmap-type-silkscreen.js.v87486.14&j/photo-sidebar-transjax-en-us.js.v90794.14&stylesheet/stylesheet-min.js&j/photo-sidebar.js.v92813.14&j/photo-context-menu-transjax-en-us.js.v90793.14&j/photo-lightbox-transjax-en-us.js.v92868.14&j/ywa.js.v89879.14&j/photo-ywa-tracking.js.v92723.14&j/occult.js.v90963.14&j/yahoo-ult.js.v92052.14&j/photo-zeus.js.v93054.14&j/photo-people-list.js.v92992.14&j/photo-button-bar.js.v92891.14&j/photo-context-menu.js.v92706.14&j/photo-lightbox.js.v93054.14&j/insitu-transjax-en-us.js.v90792.14&j/insitu-zeus.js.v91793.14&j/photo-insitu.js.v91169.14&j/photo-group-invites-transjax-en-us.js.v90793.14&j/photo-group-invites.js.v91020.14&j/tagrs_zeus-transjax-en-us.js.v93081.14&j/tagrs_zeus.js.v93081.14&j/photo-sidebar-owner-transjax-en-us.js.v91626.14&j/photo-sidebar-owner.js.v92860.14&j/photo-sidebar-admin.js.v92656.14&j/photo-geolocation-transjax-en-us.js.v92191.14&j/photo-geolocation.js.v92894.14&j/personmenu-transjax-en-us.js.v90792.14&j/personmenu-zeus.js.v92796.14&j/share-menu-zeus-transjax-en-us.js.v92581.14&j/share-menu-zeus.js.v92971.142,792 characters
Turns out that a small but vocal minority of users sit behind firewalls that restrict URL length
The algorithm we settled on was string substitution:
http://l.yimg.com/g/combo.gne?event/event-min.js&j/.H-.K.A.vNKE8&j/.CP-.U-.DE.A.vKEJx&j/.J_.BR_.CA.A.vKYke&j/.J_.DB.A.vPpBR&base/base-min.js&anim/anim-min.js&dump/dump-min.js&datatype/datatype-xml-min.js&substitute/substitute-min.js&queue-promote/queue-promote-min.js&io/io-min.js&json/json-min.js&j/.J_.DS.A.vPFJk&j/.CE-.K.A.vNy2Z&j/.B-.BY.A.vPADv&j/.H-.BY.A.vPrpi&j/.CC.A.vNiA4&j/.C-.BL.A.vPL3k&j/.CV-.CH.A.vPFSX&event-simulate/event-simulate-min.js&j/.B-.T-.CI-.C-.F.A.vPJPD&j/.CW-.CU.A.vKFrV&j/.Y-.C-.F.A.vNqG8&j/.Y.A.vLKiR&j/.B-.M-.C-.F.A.vPKTH&j/.B-.M.A.vPKTH&event/event-synthetic-min.js&j/.G-.BD.A.vNHSF&j/.G-.BO.A.vNwR2&j/.DL.A.vLPjB&j/.CX-.CY.A.vP8NB&j/.X-.W-.C-.F.A.vKPQ8&j/.X-.W-.D.A.vPzvZ&j/.Q-.BX-.K.A.vPvAp&node/node-event-simulate-min.js&j/.B-.BP.A.vNJaV&j/.CM/.BA_2.5.1-.D.A.vPzug&j/bo-.S-.C-.F.A.vNwWc&j/bo-.S-.D.A.vP5RV&cookie/cookie-min.js&j/.BZ-.D.A.vNstz&j/.B-.L-.C-.F.A.vNxPV&j/.B-.L-.BH.A.vMdVz&j/.CN-.DD.A.vLjHZ&j/.B-.O-.C-.F.A.vPpcH&j/.BM.A.vKPmx&j/.B-.O.A.vPHa6&j/.B-.Q-.BQ.A.vPBmT&j/.DR-.DG.A.vMLJp&j/.B-.BE-.C-.F.A.vPHP2&j/.U-.CG.A.vNFGP&j/.B-.BE-.D.A.vPFSX&j/.BV.A.vm3Ux&j/.Z-.DK-.D.A.vLQEc&j/.Z-.DJ-.BJ.A.vLQEc&j/.B-.I-.C-.F.A.vPKTH&stylesheet/stylesheet-min.js&j/.B-.I.A.vPLW4&j/.B-.H-.BB-.C-.F.A.vNwXV&j/.B-.N-.C-.F.A.vPADv&j/.CL.A.vN4N4&j/.B-.CL-.BW.A.vPwkv&j/.CF.A.vNC22&j/.CM-.DO.A.vPboB&j/.B-.D.A.vPGbc&j/.B-.L-.CZ.A.vPJpv&j/.B-.T-.CI.A.vPKDV&j/.B-.H-.BB.A.vPvQc&j/.B-.N.A.vPGbc&j/.B-.DM-.CO-.C-.F.A.vNwXV&j/.B-.DM-.CO.A.vNDHi&j/.BF_.D-.C-.F.A.vPGYK&j/.BF_.D.A.vPGYK&j/.B-.I-.CQ-.BK-.C-.F.A.vNwZD&j/.B-.I-.CQ-.BK.A.vLWQP&j/.B-.I-ad.E.A.vPukZ&j/.B-.R-.C-.F.A.vPfwg&j/.B-.R.A.vPBqk&j/.CB-.C-.F.A.vNwWc&j/.CB-.D.A.vPyvn&j/.DN-.BB-.D-.C-.F.A.vPs7F&j/.DN-.BB-.D.A.vPM5F
1,702 characters (40% smaller)
This fixes the problem for almost all users… but Sonicwall turns out to have a limit below 1600 characters
And then there was the XXX problem
3. Convenience methods
We noticed that on IE8/7, scrolling was very jerky
The culprit: pollers in Y.delegate() and Y.on()
We replaced both with Y.all().on(), and more customized solutions
Convenience methods have a cost
4. Fragment fetcher
On most pages, there are a lot of low percentage actions
Optimize for the 99% case; don’t load markup, CSS or JS for rarely used actions
Loading indicators can help here as well
The long-term part: a culture of performance
The old metrics are meaningless
What do we measure?
What is the best sampling rate?
Put the graphs in a place where FEs will see them
Browsers behave so differently that lumping them in together hides
successes
In order to measure just the changes you make, you need a reference
system
In closing…
YUI3 is amazing – give it a try!
If you can't have real performance, fake it
Dig deeply into the JS library you use
Measure the moments important to your page
And NEVER include XXX in a URL
Thank you!
[email protected] at: lanyrd.com/spdm
Photo creditshttp://www.flickr.com/photos/markscott/1117392453/http://www.flickr.com/photos/cybertoad/2102752062/http://www.flickr.com/photos/whiteoakart/471538245/http://www.flickr.com/photos/wwarby/3016567069/http://www.flickr.com/photos/richoz/3791167457/http://www.flickr.com/photos/lin/372711782/http://www.flickr.com/photos/cdhc/274211112/http://www.flickr.com/photos/ennor/353250218/http://www.flickr.com/photos/jensaar/386863409/http://www.flickr.com/photos/sterlic/4299631538/http://www.flickr.com/photos/candyflossblackmarket/1139767634/http://www.flickr.com/photos/bobcatrock/2653120251/
http://www.flickr.com/photos/jm2c/3677835375/http://www.flickr.com/photos/kevinkyen/4721020630/http://www.flickr.com/photos/sindykids/2666402195/http://www.flickr.com/photos/simonhua/4696240744/http://www.flickr.com/photos/inkiboo/203350186/http://www.flickr.com/photos/sahlgoode/5012048467/http://www.flickr.com/photos/sshb/3981130921/http://www.flickr.com/photos/blueskin808/1422588776/http://www.flickr.com/photos/roadsidepictures/1389358202/http://www.flickr.com/photos/boliston/3958674786/http://www.flickr.com/photos/httpwwwactionpixsmarukocom/4812699768/