Embracing YUI3 and Frontend Perf

Post on 12-May-2015

531 views 3 download

Tags:

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() {

. . .});

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

• yui-users@yahoo-inc.com

Web Performance Resources

• http://stevesouders.com/

• http://www.perfplanet.com/

• Velocity

THANKS