PAGE 2

Who am I?

 Developer Evangelist at Microsoft based in Silicon Valley, CA
 Blog: http://blogs.msdn.com/b/dorisch...
Tips & tricks that still work

http://channel9.msdn.com/Events/Build/2012/3-132
User innerHTML to Create your DOM
Use DOM Efficiently

function InsertUsername()
{
document.getElementById('user').innerHT...
Avoid Inline JavaScript
Efficiently Structure Markup

<html>
<head>
<script type="text/javascript">
function helloWorld() ...
JSON Always Faster than XML for Data
XML Representation

<!DOCTYPE glossary PUBLIC "DocBook V3.1">
<glossary><title>exampl...
Use Native JSON Methods
Write Fast JavaScript

Native JSON Methods
var jsObjStringParsed = JSON.parse(jsObjString);
var js...
Raw JS code: http://aka.ms/FastJS
Demo
High Five
Components and control flow

Repeat until neighbors list empty

Arrays

Objects and
properties

Numbers

Memory allocation...
Always start with a good profiler

F12 UI Responsiveness Tool

Windows Performance Toolkit
http://aka.ms/WinPerfKit
IE (Pipeline)
DMANIP
Hit Testing
Data
&State

Input

DOM
Tree
1
Networking

Display Tree
1

2

Parsers

3

7
4

5

8

Form...
Do we expect so much of GC to happen?
GC
What triggers a garbage collection?
•

Every call to new or implicit memory allocation reserves GC memory

•

When the poo...
demo
Results

•
•

Overall FG GC time reduced to 1/3rd
Raw JavaScript perf improved ~3x
Best practices for staying lean
•
•
•

Avoid unnecessary object creation
Use object pools, when possible
Be aware of alloc...
Internal Type System: Fast Object Types
var p1;
p1.north = 1;
p1.south = 0;

var p2;
p2.south = 0;
p2.north = 1;

Base Typ...
Create fast types and avoid type mismatches
Don’t add properties conditionally
function Player(direction) {
if (direction ...
Create fast types and avoid type mismatches
Don’t default properties on prototypes
function Player(name) {
...
};

Player....
Internal Type System: Slower Property Bags
var p1 = new Player(); //prop
bag
p1.north = 1;
p1.south = 1;

Slower Bag “{p1}...
Avoid conversion from fast type to slower property bags
Deleting properties forces conversion

function
this.n
this.e
this...
Avoid creating slower property bags
Add properties in constructor, restrict total properties

function Player() {
this.pro...
Avoid creating slower property bags

Restrict using getters, setters and property descriptors in perf critical paths
funct...
demo
Results
3.8s

•
•

Time in script execution reduced ~30%
Raw JS performance improved ~30%

2.2s
Best practices for fast objects and manipulations

• Create and use fast types
• Keep shapes of objects consistent
• Avoid...
Numbers in JavaScript
• All numbers are IEEE 64-bit floating point numbers
- Great for flexibility
- Performance and optim...
Use 31-bit integers for faster arithmetic
STACK
var north = 1;

north:
east:

function Player(north, south, east, west)
{
...
Avoid creating floats if they are not needed
Fastest way to indicate integer math is |0
var r = 0;

var r = 0;

function d...
Take advantage of type-specialization for arithmetic
Create separate functions for ints and floats; use consistent argumen...
Best practices for fast arithmetic
• Use 31-bit integer math when possible
• Avoid floats if they are not needed
• Design ...
Chakra: Array internals
Type: Int Array

01
02
03
04

var a = new Array();
a[0] = 1;
a[1] = 2.3;
a[2] = “str”;

1

Type: F...
Pre-allocate arrays
var a = new Array();
for (var i = 0; i < 100; i++) {
a.push(i + 2);
}

var a = new Array(100);
for (va...
For mixed arrays, provide an early hint
Avoid delayed type conversion and copy

var a = new Array(100000);

var a = new Ar...
Use Typed Arrays when possible

Avoids tagging of integers and allocating heap space for floats

var value = 5;

var value...
Keep values in arrays consistent
Numeric arrays treated like Typed Arrays internally
var a = [1,0x2,99.1,5];
var b = [0x10...
Keep arrays dense

Deleting elements can force type change and de-optimization
var a = new Array(1000);
//type int
...
for...
Enumerate arrays efficiently

Explicit caching of length avoids repetitive property accesses
var a = new Array(100);
var t...
Best practices for using arrays efficiently

•
•
•
•
•

Pre-allocate arrays
Keep array type consistent
Use typed arrays wh...
Avoid chattiness with the DOM
...
//for each rotation
document.body.game.getElementById(elID).classList.remove(oldClass)
d...
Avoid automatic conversions of DOM values
Values from DOM are strings by default

this.boardSize = document.getElementById...
Paint as much as your users can see
Align timers to display frames

requestAnimationFrame(animate);
setInterval(animate, 0...
demo
Results

Save CPU cycles
setTimeout(animate,

75%

0);

requestAnimationFrame(animate);

65%
Optimized JS code: http://aka.ms/FasterJS
PAGE 61
Splash screen

New host
process

App visible

Loading and
parsing
of
HTML, JS, CSS

Ready for
user

Windows Runtime
"activ...
Splash screen

App visible

App ready to use
• Can I eliminate work entirely?
• Can I optimize existing work?
• Can I defer work, or perform it in parallel?
Splash screen

App visible

App ready to use
Loading and Parsing: Package Locally
Optimize your landing Page: Use Local Data
MIME Type: text/cache-manifest
PAGE 80

twitter #devcamp

lab setup: http://bit.ly/html5setup

Blog http://blogs.msdn.com/dorischen
Optimize landing page: Load only what you need
 <script type="text/javascript" src='file1.js'

defer='defer'></script>
Further optimizations
Join us for this Free, hands-on event and learn how to build a Windows 8.1
and/or Windows Phone game in record time. We’ll...
http://bit.ly/win8OnePage

http://bit.ly/HTML5Wins8Camp
http://msdn.microsoft.com/en-us/library/windows/apps/hh465194.aspx...
• Responsive Web Design and CSS3
• http://bit.ly/CSS3Intro
• HTML5, CSS3 Free 1 Day Training
• http://bit.ly/HTML5DevCampD...
Developing High Performance Websites and Modern Apps with JavaScript and HTML5
Developing High Performance Websites and Modern Apps with JavaScript and HTML5
Developing High Performance Websites and Modern Apps with JavaScript and HTML5
Developing High Performance Websites and Modern Apps with JavaScript and HTML5
Developing High Performance Websites and Modern Apps with JavaScript and HTML5
Developing High Performance Websites and Modern Apps with JavaScript and HTML5
Developing High Performance Websites and Modern Apps with JavaScript and HTML5
Developing High Performance Websites and Modern Apps with JavaScript and HTML5
Developing High Performance Websites and Modern Apps with JavaScript and HTML5
Developing High Performance Websites and Modern Apps with JavaScript and HTML5
Developing High Performance Websites and Modern Apps with JavaScript and HTML5
Developing High Performance Websites and Modern Apps with JavaScript and HTML5
Developing High Performance Websites and Modern Apps with JavaScript and HTML5
Developing High Performance Websites and Modern Apps with JavaScript and HTML5
Developing High Performance Websites and Modern Apps with JavaScript and HTML5
Developing High Performance Websites and Modern Apps with JavaScript and HTML5
Developing High Performance Websites and Modern Apps with JavaScript and HTML5
Developing High Performance Websites and Modern Apps with JavaScript and HTML5
Upcoming SlideShare
Loading in …5
×

Developing High Performance Websites and Modern Apps with JavaScript and HTML5

5,101 views
5,027 views

Published on

Creating high performance sites and apps is crucial for every developer. In this session, we will explore the best practices and performance tricks, including startup time, UI responsiveness, and Memory efficiency to make your apps running faster and fluid. Come learn the tips, tricks, and tools for maximizing the performance of your sites and apps with JavaScript and HTML5.

Published in: Technology
1 Comment
3 Likes
Statistics
Notes
No Downloads
Views
Total views
5,101
On SlideShare
0
From Embeds
0
Number of Embeds
7
Actions
Shares
0
Downloads
66
Comments
1
Likes
3
Embeds 0
No embeds

No notes for slide

Developing High Performance Websites and Modern Apps with JavaScript and HTML5

  1. 1. PAGE 2 Who am I?  Developer Evangelist at Microsoft based in Silicon Valley, CA  Blog: http://blogs.msdn.com/b/dorischen/  Twitter @doristchen  Email: doris.chen@microsoft.com  Office Hours http://ohours.org/dorischen  Has over 15 years of experience in the software industry focusing on web technologies  Spoke and published widely at JavaOne, O'Reilly, Silicon Valley Code Camp, SD West, SD Forum and worldwide User Groups meetings  Doris received her Ph.D. from the University of California at Los Angeles (UCLA) Blog http://blogs.msdn.com/dorischen
  2. 2. Tips & tricks that still work http://channel9.msdn.com/Events/Build/2012/3-132
  3. 3. User innerHTML to Create your DOM Use DOM Efficiently function InsertUsername() { document.getElementById('user').innerHTML = userName; }
  4. 4. Avoid Inline JavaScript Efficiently Structure Markup <html> <head> <script type="text/javascript"> function helloWorld() { alert('Hello World!') ; } </script> </head> <body> … </body> </html>
  5. 5. JSON Always Faster than XML for Data XML Representation <!DOCTYPE glossary PUBLIC "DocBook V3.1"> <glossary><title>example glossary</title> <GlossDiv><title>S</title> <GlossList> <GlossEntry ID="SGML" SortAs="SGML"> <GlossTerm>Markup Language</GlossTerm> <Acronym>SGML</Acronym> <Abbrev>ISO 8879:1986</Abbrev> <GlossDef> <para>meta-markup language</para> <GlossSeeAlso OtherTerm="GML"> <GlossSeeAlso OtherTerm="XML"> </GlossDef> <GlossSee OtherTerm="markup"> </GlossEntry> </GlossList> </GlossDiv> </glossary> JSON Representation "glossary":{ "title": "example glossary", "GlossDiv":{ "title": "S", "GlossList": { "GlossEntry": { "ID": "SGML", "SortAs": "SGML", "GlossTerm": "Markup Language", "Acronym": "SGML", "Abbrev": "ISO 8879:1986", "GlossDef": { "para": "meta-markup language", "GlossSeeAlso": ["GML", "XML"] }, "GlossSee": "markup" } } } }
  6. 6. Use Native JSON Methods Write Fast JavaScript Native JSON Methods var jsObjStringParsed = JSON.parse(jsObjString); var jsObjStringBack = JSON.stringify(jsObjStringParsed);
  7. 7. Raw JS code: http://aka.ms/FastJS
  8. 8. Demo High Five
  9. 9. Components and control flow Repeat until neighbors list empty Arrays Objects and properties Numbers Memory allocations Animation loop
  10. 10. Always start with a good profiler F12 UI Responsiveness Tool Windows Performance Toolkit http://aka.ms/WinPerfKit
  11. 11. IE (Pipeline) DMANIP Hit Testing Data &State Input DOM Tree 1 Networking Display Tree 1 2 Parsers 3 7 4 5 8 Formatting 9 6 DOM API & Capabilities JavaScript Layout 2 3 7 4 5 8 6 9 Painting Compositing
  12. 12. Do we expect so much of GC to happen? GC
  13. 13. What triggers a garbage collection? • Every call to new or implicit memory allocation reserves GC memory • When the pool is exhausted, engines force a collection • Be careful with object allocation patterns in your apps - Allocations are cheap until current pool is exhausted - Collections cause program pauses - Pauses could take milliseconds - Every allocation brings you closer to a GC pause
  14. 14. demo
  15. 15. Results • • Overall FG GC time reduced to 1/3rd Raw JavaScript perf improved ~3x
  16. 16. Best practices for staying lean • • • Avoid unnecessary object creation Use object pools, when possible Be aware of allocation patterns - Setting closures to event handlers - Dynamically creating DOM (sub) trees - Implicit allocations in the engine
  17. 17. Internal Type System: Fast Object Types var p1; p1.north = 1; p1.south = 0; var p2; p2.south = 0; p2.north = 1; Base Type “{}” Type “{north}” Type “{north, south}” Base Type “{}” north 1 south 0 north 1 south 0 south 0 north 1 Type “{south}” Type “{south, north}”
  18. 18. Create fast types and avoid type mismatches Don’t add properties conditionally function Player(direction) { if (direction = “NE”) { this.n = 1; this.e = 1; } else if (direction = “ES”) { this.e = 1; this.s = 1; } ... } function Player(north,east,south,west) { this.n = north; this.e = east; this.s = south; this.w = west; } var p1 = new Player(“NE”); var p2 = new Player(“ES”); var p1 = new Player(1,1,0,0);//p1 type {n,e,s,w} var p2 = new Player(0,0,1,1);//p2 type {n,e,s,w} // p1 type {n,e} // p2 type {e,s} p1.type != p2.type p1.type == p2.type
  19. 19. Create fast types and avoid type mismatches Don’t default properties on prototypes function Player(name) { ... }; Player.prototype.n Player.prototype.e Player.prototype.s Player.prototype.w = = = = function this.n this.e this.s this.w ... } null; null; null; null; Player(name) { = null; = null; = null; = null; var p1 = new Player("Jodi"); var p2 = new Player("Mia"); var p3 = new Player("Jodi"); //p1 type{} //p2 type{} //p3 type{} var p1 = new Player("Jodi"); var p2 = new Player("Mia"); var p3 = new Player("Jodi"); //p1 type{n,e,s,w} //p2 type{n,e,s,w} //p3 type{n,e,s,w} p1.n = 1; p2.e = 1; //p1 type {n} //p2 type {e} p1.n = 1; p2.e = 1; //p1 type{n,e,s,w} //p2 type{n,e,s,w} p1.type != p2.type != p3.type p1.type == p2.type == p3.type
  20. 20. Internal Type System: Slower Property Bags var p1 = new Player(); //prop bag p1.north = 1; p1.south = 1; Slower Bag “{p1}” var p2 = new Player(); //prop bag p2.north = 1; p2.south = 1; Slower Bag “{p2}”
  21. 21. Avoid conversion from fast type to slower property bags Deleting properties forces conversion function this.n this.e this.s this.w } var p1 = Player(north,east,south,west) { = north; = east; = south; = west; new Player(); delete p1.n; function this.n this.e this.s this.w } var p1 = Player(north,east,south,west) { = north; = east; = south; = west; p1.n = 0; SLOW new Player(); // or undefined FAST
  22. 22. Avoid creating slower property bags Add properties in constructor, restrict total properties function Player() { this.prop01 = 1; this.prop02 = 2; ... this.prop256 = 256; ... // Do you need an array? } function Player(north,east,south,west) { this.n = north; this.e = east; this.s = south; this.w = west; ... // Restrict to few if possible } var p1 = new Player(); var p1 = new Player(); SLOW FAST
  23. 23. Avoid creating slower property bags Restrict using getters, setters and property descriptors in perf critical paths function Player(north, east, south, west) { Object.defineProperty(this, "n", { get : function() { return nVal; }, set : function(value) { nVal=value; }, enumerable: true, configurable: true }); Object.defineProperty(this, "e", { get : function() { return eVal; }, set : function(value) { eVal=value; }, enumerable: true, configurable: true }); ... } var p = new Player(1,1,0,0); var n = p.n; p.n = 0; ... SLOW function this.n this.e this.s this.w ... } Player(north, east, south, west) { = north; = east; = south; = west; var p = new Player(1,1,0,0); var n = p.n; p.n = 0; ... FAST
  24. 24. demo
  25. 25. Results 3.8s • • Time in script execution reduced ~30% Raw JS performance improved ~30% 2.2s
  26. 26. Best practices for fast objects and manipulations • Create and use fast types • Keep shapes of objects consistent • Avoid type mismatches for fast types
  27. 27. Numbers in JavaScript • All numbers are IEEE 64-bit floating point numbers - Great for flexibility - Performance and optimization challenge 31 bits Object pointer 31 bits 31-bit (tagged) Integers STACK FIXED LENGTH, FASTER ACCESS 1 bit 0 1 bit Boxed 32 bits Floats 32-bit Integers 32 bits 1 HEAP VARIABLE LENGTH, SLOWER ACCESS
  28. 28. Use 31-bit integers for faster arithmetic STACK var north = 1; north: east: function Player(north, south, east, west) { ... } 0x005e4148 south: var east = "east"; var south = 0.1; var west = 0x1; 0x00000003 0x005e4160 west: 0x005e4170 HEAP SLOW String “east” SLOW Number SLOW 0.1 var p = new Player(north,south,east,west); Number 0x005e4148: 0x03 represents 1: 0…01001000 0…00000011 0x1
  29. 29. Avoid creating floats if they are not needed Fastest way to indicate integer math is |0 var r = 0; var r = 0; function doMath(){ var a = 5; var b = 2; r = ((a + b) / 2); } ... var intR = Math.floor(r); function doMath(){ var a = 5; var b = 2; r = ((a + b) / 2) |0 ; r = Math.round((a + b) / 2); } // r = 3.5 SLOW STACK r: 0x005e4148 SLOW FAST STACK HEAP Number r: 0x00000007 3.5 r: 0x00000009 // r = 3 // r = 4
  30. 30. Take advantage of type-specialization for arithmetic Create separate functions for ints and floats; use consistent argument types function var dx var dy var d2 return } var var var var Distance(p1, p2) { = p1.x - p2.x; = p1.y - p2.y; = dx * dx + dy * dy; Math.sqrt(d2); point1 point2 point3 point4 = = = = {x:10, y:10}; {x:20, y:20}; {x:1.5, y:1.5}; {x:0x0AB, y:0xBC}; Distance(point1, point3); Distance(point2, point4); SLOW function DistanceFloat(p1, p2) { var dx = p1.x - p2.x; var dy = p1.y - p2.y; var d2 = dx * dx + dy * dy; return Math.sqrt(d2); } function DistanceInt(p1,p2) { var dx = p1.x - p2.x; var dy = p1.y - p2.y; var d2 = dx * dx + dy * dy; return (Math.sqrt(d2) | 0); } var point1 = {x:10, y:10}; var point2 = {x:20, y:20}; var point3 = {x:1.5, y:1.5}; var point4 = {x:0x0AB, y:0xBC}; DistanceInt(point1, point2); DistanceFloat(point3, point4); FAST
  31. 31. Best practices for fast arithmetic • Use 31-bit integer math when possible • Avoid floats if they are not needed • Design for type specialized arithmetic
  32. 32. Chakra: Array internals Type: Int Array 01 02 03 04 var a = new Array(); a[0] = 1; a[1] = 2.3; a[2] = “str”; 1 Type: Float Array 1 2.3 Type: Var Array 1 2.3 “str”
  33. 33. Pre-allocate arrays var a = new Array(); for (var i = 0; i < 100; i++) { a.push(i + 2); } var a = new Array(100); for (var i = 0; i < 100; i++) { a[i] = i + 2; } FAST SLOW 0 ? 0 ?+1 ?? … 100
  34. 34. For mixed arrays, provide an early hint Avoid delayed type conversion and copy var a = new Array(100000); var a = new Array(100000); a[0] = “hint”; for (var i = 0; i < a.length; i++) { a[i] = i; } ... //operations on the array ... a[99] = “str”; SLOW for (var i = 0; i < a.length; i++) { a[i] = i; } ... //operations on the array ... a[99] = “str”; FAST
  35. 35. Use Typed Arrays when possible Avoids tagging of integers and allocating heap space for floats var value = 5; var value = 5; var a = new Array(100); a[0] = value; a[1] = value / 2; a[2] = "text"; // 5 - tagged // 2.5 - boxed // "text" – var array var a = new Float64Array(100); a[0] = value; // 5 - no tagging required a[1] = value / 2; // 2.5 - no boxing required a[2] = "text"; // 0 var a = new Int32Array(100); a[0] = value; // 5 - no tagging required a[1] = value / 2; // 2 - no tagging required a[2] = "text"; // 0 SLOW FAST
  36. 36. Keep values in arrays consistent Numeric arrays treated like Typed Arrays internally var a = [1,0x2,99.1,5]; var b = [0x10,8,9]; function add(a,i,b,j) { return a[i] + b[j]; } add(a,0,b,0); add(a,1,b,1); SLOW //mixed array //mixed array var a = [1,5,8,9]; var b = [0x02,0x10,99.1]; array function add(a,i,b,j) { return a[i] + b[j]; } add(a,0,b,0); add(a,1,b,1); FAST //int array //float
  37. 37. Keep arrays dense Deleting elements can force type change and de-optimization var a = new Array(1000); //type int ... for (var i = 0; i < boardSize; i++) { matrix[i] = [1,1,0,0]; } var a = new Array(1000); //type int ... for (var i = 0; i < boardSize; i++) { matrix[i] = [1,1,0,0]; } //operating on the array ... delete matrix[23]; ... //operating on the array //operating on the array ... matrix[23] = 0; ... //operating on the array SLOW FAST
  38. 38. Enumerate arrays efficiently Explicit caching of length avoids repetitive property accesses var a = new Array(100); var total = 0; var a = new Array(100); var total = 0; for (var item in a) { total += item; }; cachedLength = a.length; a.forEach(function(item){ total += item; }); for (var i = 0; i < cachedLength; i++) { total += a[i]; } for (var i = 0; i < a.length; i++) { total += a[i]; } SLOW FAST
  39. 39. Best practices for using arrays efficiently • • • • • Pre-allocate arrays Keep array type consistent Use typed arrays when possible Keep arrays dense Enumerate arrays efficiently
  40. 40. Avoid chattiness with the DOM ... //for each rotation document.body.game.getElementById(elID).classList.remove(oldClass) document.body.game.getElementById(elID).classList.add(newClass) ... JavaScript var element = document.getElementById(elID).classList; JavaScript //for each rotation element.remove(oldClass) element.add(newClass) ... DOM DOM
  41. 41. Avoid automatic conversions of DOM values Values from DOM are strings by default this.boardSize = document.getElementById("benchmarkBox").value; for (var i = 0; i < this.boardSize; i++) { “25” for (var j = 0; j < this.boardSize; j++) { “25” ... } } //this.boardSize is SLOW //this.boardSize is this.boardSize = parseInt(document.getElementById("benchmarkBox").value); for (var i = 0; i < this.boardSize; i++) { for (var j = 0; j < this.boardSize; j++) { ... } } //this.boardSize is 25 //this.boardSize is 25 FAST (25% marshalling cost reduction in init function)
  42. 42. Paint as much as your users can see Align timers to display frames requestAnimationFrame(animate); setInterval(animate, 0); setTimeout(animate, 0); MORE WORK setInterval(animate, 1000 / 60); setTimeout(animate, 1000 / 60); LESS WORK
  43. 43. demo
  44. 44. Results Save CPU cycles setTimeout(animate, 75% 0); requestAnimationFrame(animate); 65%
  45. 45. Optimized JS code: http://aka.ms/FasterJS
  46. 46. PAGE 61
  47. 47. Splash screen New host process App visible Loading and parsing of HTML, JS, CSS Ready for user Windows Runtime "activated" event "DOMContentLoaded" event Navigation Tile click
  48. 48. Splash screen App visible App ready to use
  49. 49. • Can I eliminate work entirely? • Can I optimize existing work? • Can I defer work, or perform it in parallel?
  50. 50. Splash screen App visible App ready to use
  51. 51. Loading and Parsing: Package Locally
  52. 52. Optimize your landing Page: Use Local Data
  53. 53. MIME Type: text/cache-manifest
  54. 54. PAGE 80 twitter #devcamp lab setup: http://bit.ly/html5setup Blog http://blogs.msdn.com/dorischen
  55. 55. Optimize landing page: Load only what you need  <script type="text/javascript" src='file1.js' defer='defer'></script>
  56. 56. Further optimizations
  57. 57. Join us for this Free, hands-on event and learn how to build a Windows 8.1 and/or Windows Phone game in record time. We’ll cover everything you need to create, upload and publish an amazing game. Expert developers will outline different game frameworks and give you the tools you need to start building. They’ll also explain how to add graphics, level and sound to game starter kits, while sharing other cool ways to make the game your own. In one jam-packed day of learning and coding, you can turn your idea into reality! Register today for a local Game On event. December 4, 2013 December 5, 2013 San Francisco, CA Mountain View, CA http://aka.ms/gameonsf http://aka.ms/gameonsvc
  58. 58. http://bit.ly/win8OnePage http://bit.ly/HTML5Wins8Camp http://msdn.microsoft.com/en-us/library/windows/apps/hh465194.aspx http://Aka.ms/brockschmidtbook  http:/dev.windows.com PAGE
  59. 59. • Responsive Web Design and CSS3 • http://bit.ly/CSS3Intro • HTML5, CSS3 Free 1 Day Training • http://bit.ly/HTML5DevCampDownload • Using Blend to Design HTML5 Windows 8 Application (Part II): Style, Layout and Grid • http://bit.ly/HTML5onBlend2 • Using Blend to Design HTML5 Windows 8 Application (Part III): Style Game Board, Cards, Support Different Device, View States • http://bit.ly/HTML5onBlend3 • Feature-specific demos • http://ie.microsoft.com/testdrive/ • Real-world demos PAGE • http://www.beautyoftheweb.com/

×