embracing yui3 and frontend perf
DESCRIPTION
Morgan's knowledge sharing presentation.TRANSCRIPT
Embracing YUI 3 & Frontend Performance
Morgan Cheng, Jan 6th 2011
YUI 3
• Lighter
• Faster
• Easier to use
YUI 2 to YUI 3
YUI 2 sample module YAHOO.namespace(‘MyProject’);
(function() {
var MODULE_NAME=“MyProject”, Dom = YAHOO.util.Dom;
YAHOO.MyProject.MyDialog = function() { . . . };
}());
Another YUI 2 sample moduleYAHOO.namespace(‘MyProject’);
(function() { var MODULE_NAME=“MyProject”, Dom = YAHOO.util.Dom Event = YAHOO.util.Event;
YAHOO.MyProject.MyPage = { init: function() { }, . . . }; Event.onDOMReady(YAHOO.MyProject.MyPage.init, null,
YAHOO.MyProject.MyPage);}());
Not Enough for Mash-up Page
Limitation
• YAHOO property can be overwritten…
YAHOO.widget.HelloWorld = something; // by one developer
…
YAHOO.widget.HelloWorld = another; // by another developer
YUI 3 module
YUI.add(“myModule”, function(Y) { Y.namespace(‘myproject’).mod = function() { }; }, “0.0.1”, //module version {requires: [‘node’]} // dependecies);
Use YUI 3 module
YUI().use(“myModule”, function(Y) { var m = new Y.myProject.mod; . . .});
This might be easy to read:var yui = YUI();yui. use(“myModule”, function(Y) { var m = new Y.myProject.mod; . . .});
SandboxingYUI().use(“myModule”, function(Y) { var m = new Y.myProject.mod;});
YUI().use(“node”, function(Y) { //no myProject for this Y});
DOM
<div id=“menu”> <h1>B1 Canteen Menu</h1>
<ul> <li>Fish</li> <li class=“promotion”>Noodle</li> <li class=“promotion”>Meat</li> <li>Rice</li> <li>Tomato</li> </ul></div>
In YUI 2
• To get <li> element with “promotion” class under element with id “menu”
var Dom = YAHOO.util.Dom;var el = Dom.get(‘menu’);var promotedItems = Dom.getElementsByClassName(‘promotion’, ‘li’, el);
Selector API in YUI 3
• One-liner
YUI().use(‘node’, function(Y) { var promtedItems = Y.all(‘#menu li.promotion’);});
Selector Best Practice
• Prefer “#id”
• Prefer simple selector over complex selector
YUI 2 Selector Utility
• http://developer.yahoo.com/yui/selector/
• But, not chainable– returning raw Dom elements
Node & NodeList
• Wrapper of DOM elements
• From function-based to object-basedIn YUI 2
var el = YAHOO.util.Dom.get(‘id’); YAHOO.util.Dom.addClass(el, ‘className’);In YUI 3
Y.one(‘id’).addClass(‘className’);
YUI 3 Chainable
YUI().use(‘node’, function(Y) { Y.all(“#menu li”) .each(function(node, i, ctx) { if ( i % 2) { node.addClass(‘even’).removeClass(‘disable’); } }) .setStyle(‘color, ‘red’); });
Event
• Event Facade
YUI().use(‘event’, ‘node’, function(Y) { Y.one(‘id’).on(‘click’, function(e) { Y.log(e.currentTarget); e.preventDefault(); });});
Wait, but how
does these stuff get loaded into page?
Seed File
<script src="http://yui.yahooapis.com/3.2.0/build/yui/yui-min.js"></script>
YUI().use(‘node’, function(Y) {});
Seed File with Loader
<script type="text/javascript" src="http://yui.yahooapis.com/combo?3.2.0/build/yui/yui-min.js&3.2.0/build/loader/loader-min.js"></script>
YUI().use(‘node’, function(Y) {});
Traditional Way
<script type="text/javascript" src="http://yui.yahooapis.com/combo?3.2.0/build/yui/yui-min.js&3.2.0/build/loader/loader-min.js&3.2.0/build/oop/oop-min.js&3.2.0/build/dom/dom-min.js&3.2.0/build/dom/dom-style-ie-min.js&3.2.0/build/event-custom/event-custom-base-min.js&3.2.0/build/event/event-base-min.js&3.2.0/build/pluginhost/pluginhost-min.js&3.2.0/build/node/node-min.js&3.2.0/build/event/event-delegate-min.js"></script>
YUI 3 Dependency Magic
• Ramp-up
• Combine
JavaScript Blocks
Script Blocks Page Rendering
<script type=“text/javascript” src=“long-time.js”></script>
<img src=“I-am-bocked.png”></img>
Script Blocks Script
<script type=“text/javascript” src=“long-time.js”></script>
<script type=“text/javascript” src=“I-am-bocked.js”></script>
post-IE8 browsers do asynchronous downloading
Non-blocking JavaScript
• defer attribute• async attribute• iframe• document.write• XHR injection• Commented Javascript• JavaScript downloaded as Image & Object• …
Dynamic Script Tag
function createScript(js) { var script = document.createElement(‘script’); script.type = ‘text/javascript’; script.async = “true”; var head = document.getElementsByTagname(‘head’)[0]; head.appendChild(script); }
Execution Order Matters
• Execution order is not guaranteed to be preserved for asynchronous script loading
• YUI 3 is born to solve execution order problem– each module payload is not executed until all
dependencies are ready
Don’t Get Excited Too Early
Deficiency in YUI 3 Loader
• YUI().use blocks each other
YUI().use(‘node’, function() {. . .
});
YUI().use(‘event’, function() { . . .});
Deficiency in YUI 3 Loader
• Disabling combo makes each module loaded in sequence
YUI({ combine: false}).use(‘node’, ‘event’, function() {
. . .});
Prefetch YUI Loader hack
http://bazaar.launchpad.net/~launchpad-pqm/lazr-js/toolchain/annotate/188/src-js/lazrjs/loader/prefetch.js
Flickr Lesson #1
• Firewall can cut your long URL http://yui.yahooapis.com/combo?3.2.0/build/yui/yui-min.js&3.2.0/build/oop/oop-min.js&3.2.0/build/event-
custom/event-custom-min.js&3.2.0/build/event/event-base-min.js&3.2.0/build/pluginhost/pluginhost-min.js&3.2.0/build/attribute/attribute-min.js&3.2.0/build/dom/dom-min.js&3.2.0/build/dom/dom-style-ie-min.js&3.2.0/build/node/node-min.js&3.2.0/build/event/event-delegate-min.js&3.2.0/build/base/base-min.js&3.2.0/build/anim/anim-min.js&3.2.0/build/node/align-plugin-min.js&3.2.0/build/classnamemanager/classnamemanager-min.js&3.2.0/build/intl/intl-min.js&3.2.0/build/console/lang/console.js&3.2.0/build/event/event-synthetic-min.js&3.2.0/build/event/event-focus-min.js&3.2.0/build/widget/widget-min.js&3.2.0/build/dump/dump-min.js&3.2.0/build/substitute/substitute-min.js&3.2.0/build/console/console-min.js&3.2.0/build/plugin/plugin-min.js&3.2.0/build/console/console-filters-min.js&3.2.0/build/cookie/cookie-min.js&3.2.0/build/dom/dom-style-ie-min.js&3.2.0/build/event/event-resize-min.js&3.2.0/build/event/event-mouseenter-min.js&3.2.0/build/dd/dd-min.js&3.2.0/build/dd/dd-gestures-min.js&3.2.0/build/dd/dd-drop-plugin-min.js&3.2.0/build/dd/dd-plugin-min.js&3.2.0/build/event/event-touch-min.js&3.2.0/build/event-gestures/event-move-min.js&3.2.0/build/dd/dd-gestures-min.js&3.2.0/build/dataschema/dataschema-base-min.js&3.2.0/build/dataschema/dataschema-array-min.js&3.2.0/build/cache/cache-base-min.js&3.2.0/build/querystring/querystring-stringify-simple-min.js&3.2.0/build/io/io-base-min.js&3.2.0/build/json/json-min.js&3.2.0/build/dataschema/dataschema-json-min.js&3.2.0/build/dataschema/dataschema-text-min.js&3.2.0/build/dataschema/dataschema-xml-min.js&3.2.0/build/datasource/datasource-min.js
Flickr Lesson #2
• Sexy URL is not welcome http://… &xxw.js&xxx.js&…
Multiple Pages
• Page A– module A + B + C + D + E + X
• Page B– module A + B + C + D + E + Y
• Page C– module A + B + C + D + Z
YUI 3 IN ACTION
Widget Class Diagram
Code Reuse
• Y.extend• Y.augment • Y.clone //deep copy by value• Y.merge //mix-in multiple objects• Y.aggregate
Powerful Y.mix
Y.mix(r, s, ov, wl, mode, merge)
mode:0. object to object1. prototype to prototype2. prototype to prototype and object props3. prototype to object 4. object to prototype
EventTarget
• publish• fire• on• before• after
Attribute
• set
• get
Base
• Initializer
• destrutor
• static property NAME as event prefix
Widget
• render– renderUI– bindUI– syncUI
Plugin
Y.namespace('QPlus').DigPlugin = Y.Base.create('Dig', Y.Plugin.Base, [],
{ //prototypal properties
},{ // static properties});
Plugin Prototypal Properties
• Initializer
• destuctor
Plugin Static Properties
• NS– Mandatory– Used as host property name to reference plugin
Use Plugin
• plug– Trigger initializer
• unplug– Trigger destructor
AOP in YUI3
• doBefore/onHostEvent/doAfter
Y.SamplePlugin = Y.Base.create(‘sample’, Y.Plugin.Base, [],{ initializer: function() { this.doBefore(‘someMethod’, function() { … } ); }},{ NS: ‘sample’});
Custom Event
• Application Level
• De-coupling
• Identified by string
YUI 2 Custom Event
this.myEvent = new YAHOO.util.CustomEvent(‘myEvent’);
this.myEvent.fire();
instance.myEvent.subscribe(doSomething);
YUI 3 Custom Event
Y.fire(‘chengguan-coming’, 1, 2, 3);
Y.on(‘chengguan-coming’, function(arg1, arg2, arg3) {
. . .});
Advanced Custom Event
this.publish(‘myEvent’, { broadcast: 2, //broadcast to all YUI instances defaultFn: handler // default event handler} );
this.fire(‘myEvent’);
instance.on(‘myEvent’, doSomething);
Consistent Event API
instance.on(‘click’, onClick);
instance.on(‘myEvent’, doSomething);
Synthetic Event
• Extend DOM event
Y.Event.define(‘flick’, { on: function(node, subscription, notifier) { }, detach: function(node, subscription notifier) { }});
FRONTEND PERFORMANCE IMPROVMENTS
No iframe
• iframe is slow
• iframe requires one more HTTP roundtrip
• iframe makes your application complicated
Flush Early
• Flush early and user view result early
• Flush early and external resources starts downloading early
MVC might hurt your performance
Model
Controller
View
How ySymfony MVC works
<head></head><body> <div id=“hd”></div> <div id=“bd”> <?php echo $sf_content?> </div> <div id=“ft”></div></body>
Action
Lib
Template
Enable Early Flush in ySymfony
• Don’t use layout– setLayout(false)
• Fetch partial and flush it in Action– getPartial– flush
• Customize web response class to avoid head() after flush()
Don’t<html> . . .
<body><div>
<div id=‘hd’></div> <?php flush(); ?>
<? // some browser would not render till getting closing tag ?>
<div id=‘bd’></div> <?php flush(); ?>
<div id=‘ft’></div></div>
</body></html>
Do
<html> . . .
<body> <div id=‘hd’></div> <?php flush(); ?>
<div id=‘bd’></div> <?php flush(); ?>
<div id=‘ft’></div></body>
</html>
JavaScript Loading Strategy
JavaScript Loading Strategy
• Dynamic Script Tag
• Concatenate JavaScript into single file with FUSE
Users are Not Patient
• User might start interact with the page before its JavaScript module is loaded
• It is not good to not respond to user interaction
Put User Actions into Queue
Event-Binder: A Tale of Two JavaScripts
• Inline Script– Prevent default behavior– Show progressive UI– Put event into queue
• External Script– Flush events from queue– Hide progressive UI– Remove former event handler
Just at Scratch Line
YUI 3 Resources
• http://developer.yahoo.com/yui/3/
• http://yuiblog.com/
• http://twitter.com/miraglia/yui/members
Web Performance Resources
• http://stevesouders.com/
• http://www.perfplanet.com/
• Velocity
THANKS