more secrets of javascript libraries
TRANSCRIPT
More Secrets of JavaScript Libraries
Nate Koechley, Andrew Dupont,Becky Gibson, John Resig
4x 10min talks with Q&A at the end.
Getting LoadedEasier development. Better performance.
Get & LoaderEasier development. Better performance.
The Problems
JavaScript loading blocks page rendering.
More !les increases blocking.
We know a single !le is best:
But in practice...
Widgets & Plugins may have various prerequisites.
<script src="jquery/jquery-1.2.2.pack.js"/>
<script src="jquery/chili/chili.js"/>
<script src="jquery.cookie.js"/>
<script src="jquery.clickmenu.pack.js"/>
<script src="jquery.columnmanager.js"/>
<script src="yahoo-dom-event.js"/>
<script src="element-min.js"/>
<script src="connection-min.js"/>
<script src="tabview-min.js"/>
Sites often use multiple unrelated JavaScript !les.
<script src="prototype.js"/>
<script src="scriptaculous.js"/>
<script src="csiManager.js"/>
<script src="StorageManager.js"/>
<script src="main.js"/>
<script src="urchin.js">
Larger projects usemultiple !les for
"exibility & optimization
<script src="yui-base.js"/>
<script src="oop.js"/>
<script src="event.js"/>
<script src="attribute.js"/>
<script src="base.js"/>
<script src="dom.js"/>
<script src="node.js"/>
<script src="widget.js"/>
<script src="dd.js"/>
<script src="slider/slider.js/">
<script src="dd.js"/>
dd
dd-ddm-base
dd-ddm
dd-drag
dd-proxy
dd-constrain
dd-drop
dd-plugin
dd-drop-plugin
Most !les are order-dependent.
Other !les aren’tneeded right away.
And it’s nice to easily toggle between -raw.js, -min.js,
and -debug.js versions.
three "avors of each
fully-commented
-debug with logging
-min for deployment
So, our goals:
Features• Handle prerequisies without duplication
• Manage order dependency
• Per-module "exibility
• Fast toggling between "avors
• Continue fetching onDemand
• Minimize HTTP requestsand not block rendering
That’s what YUI’s Get & Loader Utilities do.
They’re partners.
Loader Get
Loader Get ComboHandler
Loader Get
The “seed” !le.
Meta data.
Con!g options.
Helpers/Sugar.
Combo
Creates new nodes & src’s.
Non-blocking.
Cross-domain.
GET not POST.
Parses request.
Concats modules if !rst.
Edge-caches.
Loads anything:
• Library !les
• Your own !les
• JS, CSS, JSON, ...
• Urchin.js, badges, includes, ...
Easily de!ne your resources
// one or more external modules // that can be loaded along side of YUI
modules: { json_org: { fullpath: "http://www.json.org/json.js" }, json2_org: { fullpath: "http://www.json.org/json2.js" } }
And their relationships
modules: { dom: { requires: ['event'], submodules: { 'dom-base': { requires: ['event'] }, 'dom-style': { requires: ['dom-base'] }, 'dom-screen': { requires: ['dom-base', 'dom-style'] }, selector: { requires: ['dom-base'] } } },
With !ne-grained control
name
type
path
fullpath
requires
optional
supersedes
after
rollup
Once the seed is on the page:
<script src="yui-min.js"/>
<script>
YUI().use("slider", function(Y) {
// Slider available and ready for use.
});
</script>
Other cool features in Get:
Choose where the nodes go.
Purge After Reading
Bene!ts
• Easy to use.
• No typos. Less to manage.
• Much faster performance.
• Extensive "exibility.
• Nice support for lazy-loading.
• Library agnostic.
[email protected]/yui/3/yui/developer.yahoo.com/yui/3/get/github.com/yui
Meta-Language Frameworks
The code you write is transformed before a browser consumes it
Google Web Toolkit(turns Java into
JavaScript)
Pyjamas(turns Python into
JavaScript)
Cappuccino(turns “Objective-J”
into JavaScript)
Some of them are lightweight...
Narrative JS(adds “sleep”-like
functionality to JS)
function waitForButton() { // do some work // create our notifier var notifier = new EventNotifier(); // attach our notifier to the button document.getElementById("myButton").onclick = notifier; // wait for the button to be clicked notifier.wait->(); // do more work}
Google Caja(turns JavaScript into
safer JavaScript)
var blogComment = document.createElement('div');blogComment.innerHTML = "<b>user entered text " + "which happens to contain a script " +"tag.</b><script defer>alert('muahahaa');</scr" + "ipt>";document.getElementById("result").appendChild(blogComment);
___.loadModule({'instantiate': function (___, IMPORTS___) {var moduleResult___ = ___.NO_RESULT;var $v = ___.readImport(IMPORTS___, '$v', {'getOuters': {'()': { }},'ro': {'()': { }},'so': {'()': { }},'initOuter': {'()': { }},'cm': {'()': { }},'s': {'()': { }}});var $dis = $v.getOuters();$v.initOuter('onerror');try {{
$v.so('blogComment', $v.cm($v.ro('document'),'createElement', [ 'div' ]));$v.s($v.ro('blogComment'), 'innerHTML','<b>user entered text which happens to contain a script '+'tag.</b><script defer>alert(\'muahahaa\');</scr'+ 'ipt>');moduleResult___ = $v.cm($v.cm($v.ro('document'),'getElementById', [ 'result' ]),'appendChild', [ $v.ro('blogComment') ]);}} catch (ex___) {___.getNewModuleHandler().handleUncaughtException(ex___,$v.ro('onerror'), 'testbed/', '2');}return moduleResult___;},'cajolerName': 'com.google.caja','cajolerVersion': '3339M','cajoledDate': 1237011597543});}
Why?
GWT gets to use the Java toolset
Cappuccino gets to introduce new syntax
and new features
Let’s say you wantRuby-style
“catch-all” methods
object.methodName(arg);
object.callMethod("methodName", arg);
[object methodName];
Fine, but nowyou’re more distant
from the code
Harder to debug
Longer feedback loop
It’s athicker abstraction
John’s blog posthttp://is.gd/bKwl
Abstractions leak...what happens when
stu! goes wrong?
Francisco’s Responsehttp://is.gd/aJ36
All frameworksare abstractions
Yeah, abstractions leak, but we all use
them anyway
MORAL:
Abstractionsare trade-o!s
Thicker abstractions have more hassle, but o!er greater rewards
Which wayshould you go?
Think about up-front cost
and ongoing cost
Use whatmakes senseto your head
Consider:We’re “stuck”
with JavaScript
!"#$%&'($)%*++",,-.-$-/0
1"+20%3-.,'4
5'6'%*++",,-.-$-/0%7"#)
819%&".%*++",,-.-$-/0%*(+:-/"+/
;
<'=%>%!"#,'4,%?"'=$"%5'4@/%8A=$"A"4/%
*++",,-.-$-/0
>
>B%90%,-/"%8C%#++",,-.$"
%D%-/@,%E=%;FGHI
F
>B%90%,-/"%8C%#++",,-.$"
%D%-/@,%E=%;FGHI
J
;B%?"'=$"%K-/:%5-,#.-$-/-",%)'4@/%E,"%A0%
,-/"
L
;B%?"'=$"%K-/:%5-,#.-$-/-",%)'4@/%E,"%A0%
,-/"
H
MB%*))-4N%*MM0%-,%/''%:#()%#4)%K-$$%(E-4%
A0%)",-N4
O
MB%*))-4N%*MM0%-,%/''%:#()%#4)%K-$$%(E-4%
A0%)",-N4
P
MB%*))-4N%*MM0%-,%/''%:#()%#4)%K-$$%(E-4%
A0%)",-N4
-,%)'-4N%-/
MQ
MB%*))-4N%*MM0%-,%/''%:#()%#4)%K-$$%(E-4%
A0%)",-N4
-,%)'-4N%-/
-,%)'-4N%-/
MM
MB%*))-4N%*MM0%-,%/''%:#()%#4)%K-$$%(E-4%
A0%)",-N4
-,%)'-4N%-/
-,%)'-4N%-/
R8%-,%)'-4N%-/
M;
*$$%/:","%+'A=#4-",%#("%)'-4N%-/
M>
*!8*%D% *++",,-.$"%!-+:%84/"(4"/%*==$-+#/-'4,
MF
*!8*%D%&:#/%-,%-/S
! *++",,-.$"%!-+:%84/"(4"/%*==$-+#/-'4,
! &>T%C="+-U-+#/-'4V%$-2"%W<97V%TCCV%X97%"/+B
! &-/:-4%?('/'+'$,%Y%Z'(A#/,%&'(2-4N%3('E=%K:-+:%-,%
=#(/%'U%&*8%D%&".%*++",,-.-$-/0%84-/-#/-["
! 84%7#,/%T#$$%C/#/E,
! 8A=$"A"4/")%-4%Z-("U'GV%8\O%K-/:%]="(#%#4)%C#U#(-%
E4)"(%)"["$'=A"4/
! 3#-4-4N%-4+("#,-4N%,E=='(/%.0%.('K,"(,V%&".%/''$2-/,%
#4)%#,,-,/-["%/"+:4'$'N-",
MJ
*!8*%]["([-"K
! *))%('$"%,"A#4/-+,%/'%,+(-=/")%R8%"$"A"4/,
! R=)#/"%,/#/"%-4U'(A#/-'4%)04#A-+#$$0
! 9#2"%-/"A,%U'+E,#.$"%[-#%/#.-4)"G%#//(-.E/"
! *))%2"0.'#()%"["4/%:#4)$-4N
^9-A-+%/:"%2"0.'#()%.":#[-'(%'U%/:"%(-+:%+$-"4/%R8
^9-4-A-_"%/#.%2"0%4#[-N#/-'4
! *))%$-["%("N-'4%-4U'%#4)%4'/-U-+#/-'4%/'%,E=='(/%*6#G
ML
*!8*%\G#A=$"%D%<(""
!'$"%`%/(""a'4%'E/"(%+'4/#-4"(b
!'$"% %̀/(""-/"A
"G=#4)")`/(E"a'4%'="4%*U(-+#%4')"b
!'$"%`%/(""-/"A"G=#4)")`U#$,"a'4%+$',")%*E,/(#$-#%4')"b
!'$"%`%/(""-/"A,"$"+/")`/(E"a'4%:-N:$-N:/")%\N0=/%+:-$)%4')"%K-/:%4'%+:-$)("4b
MH
*!8*%!'$",
! $-42! +'A.'.'GV%'=/-'4! +:"+2.'G! (#)-'V%(#)-'N('E=! .E//'4! =('N(",,.#(! ,$-)"(! ,=-4.E//'4! /(""V%/(""-/"A! #$"(/
! #==$-+#/-'4! =(","4/#/-'4! N('E=! N(-)V%N(-)+"$$! /#.V%/#.+'4/#-4"(V%/#.$-,/V%/#.=#4"$! $-,/V%$-,/-/"A! A"4E.#(V%A"4E! /''$.#(! A'("cc
MO
*!8*D%%C/#/",
9#40%A'("%ccB
85!\Z)",+(-.").0B%$#."$$").0
85!\Z'K4,V%:#,='=E=
T5*<*[#$E"A-4V%[#$E"A#GV%
[#$E"4'K
/(E"%d%U#$,""G=#4)")
/(E"%d%U#$,"("#)'4$0
/(E"%d%U#$,")-,#.$")
/(E"%d%U#$,"%d%A-G")+:"+2")
e#$E",C/#/"
MP
*!8*%7#4)A#(2%!'$",
! 9#2",%U-4)-4N%#4)%4#[-N#/-4N%/'%,"+/-'4,%'U%/:"%=#N"%
"#,-"(^ !""#$%&'$()
^ *&))+,
^ -(."#+.+)'&,/
^ -()'+)'$)0(
^ 1&$)
^ 2&3$4&'$()
^ 5+&,%6
;Q
7#4)A#(2,%\G#A=$"
;M
7#4)A#(2,%\G#A=$"
.#44"(
;;
7#4)A#(2,%\G#A=$"
.#44"(
f#[-N#/-'4
;>
7#4)A#(2,%\G#A=$"
.#44"(
f#[-N#/-'4
9#-4
;F
7#4)A#(2,%\G#A=$"
.#44"(
f#[-N#/-'4
9#-4
+'4/"4/-4U'
;J
7#4)A#(2%\G#A=$"
g)-[%)'6'<0="`h)-6-/B$#0'E/BT'4/"4/?#4"h%("N-'4`h/'=h%
+$#,,`h.#44"(h%('$"`h.#44"(hi
g,=#4%+$#,,`h$'N'hi&".*MM0gj,=#4i%
%%% gj)-[igIDD%"4)%'U%/'=%DDi
%%% g)-[%-)`h$"U/h%)'6'<0="`h)-6-/B$#0'E/BT'4/"4/?#4"h%("N-'4`h$"U/h%
('$"`h4#[-N#/-'4hi
gIDD%<(""%N'",%:"("%DDi
%%% gj)-[igIDD%"4)%'U%$"U/%DDi
%%% g)-[%-)`h+'4/"4/h%)'6'<0="`h)-6-/B$#0'E/BT'4/"4/?#4"h%/-/$"`hT'4/"4/h%
('$"`hA#-4h%#(-#D$-["`h#,,"(/-["h%#(-#D#/'A-+`h/(E"h%i
%%%%%%%% 84U'%U('A%,"$"+/")%/(""%-/"A%-,%$'#)")%:"("
%%% gj)-[igIDD%"4)%'U%+"4/"(%DDi
%%% g)-[%)'6'<0="`h)-6-/B$#0'E/BT'4/"4/?#4"h%("N-'4`h.'//'Ah%
('$"`h+'4/"4/-4U'h% i
gIDD%U''/"(%N'",%:"("%DDi
%%% gj)-[igIDD%"4)%'U%.'//'A%DDi
;L
*!8*%7-["%!"N-'4,
! ?"(+"-[#.$"%,"+/-'4,%#("%-)"4/-U-")%K-/:%("N-'4%('$"
! 7-["%-4)-+#/",%("N-'4%-,%E=)#/")
^ e#$E",%'Uk%]UUV%?'$-/"V%*,,"(/-["V%!E)"
! */'A-+%-)"4/-U-",%/:"%"G/"4/%'U%E=)#/",^ <(E"%^%"4/-("%("N-'4%-,%E=)#/")%#4)%("$"[#4/
^ Z#$,"%^%'4$0%+:#4N")%"$"A"4/%4""),%/'%."%=(","4/")%/'%E,"(
;H
7-["%!"N-'4%\G#A=$"
;O
7-["%!"N-'4%\G#A=$"
gIDD%A",,#N"%=("[-"K%=#4"%DDi
g)-[%-)`hA",,#N"h%)'6'<0="`h)-6-/B$#0'E/BT'4/"4/?#4"h%
("N-'4`h+"4/"(h%A-4C-_"`h;Qh
('$"`h("N-'4h%#(-#D$-["`h#,,"(/-["h%#(-#D#/'A-+`h/(E"h%i
9",,#N"%T'4/"4/,%$'#)")%:"("
gj)-[i%
gIDD%"4)%'U%hA",,#N"h%DDi
;P
CEAA#(0
! lC%<''$2-/,%#("%-A=$"A"4/-4N%*!8*%D%E,"%/:"AI
^ 5'6'%)-6-/,%#("%#$$%UE$$0%#++",,-.$"
! *!8*%A#2",%*6#G%#++",,-.$"
! 9#2"%0'E(%K".,-/",%)04#A-+%*f5%#++",,-.$"I
8A='(/#4+"%'U%m"0.'#()
Performance and Testing
John Resig
Performance
Analyzing Performance! Optimizing performance is a huge
concern: Faster code = happy users!
! Measure execution time
! Loop the code a few times
! Measure the di!erence:! "new Date#.getTime"#;
Stack Pro$ling! jQuery Stack Pro$ler
! Look for problematic methods and plugins
! http://ejohn.org/blog/deep%pro$ling%jquery%apps/
Accuracy of JavaScript Time
http://ejohn.org/blog/accuracy-of-javascript-time/
We’re measuring the performance ofJavaScript from within JavaScript!
15ms intervals ONLY!
Error Rate of 50-750%!
Performance Tools! How can we get good numbers?
! We have to go straight to the source: Use the tools the browsers provide.
! Tools:! Firebug Pro$ler! Safari Pro$ler
! "Part of Safari 4#! IE 8 Pro$ler
Firebug Pro$ler
Safari 4 Pro$ler
IE 8 Pro$ler
FireUnit! A simple JavaScript test suite embedded in
Firebug.
! http://$reunit.org/
FireUnit Pro$le Data
{
"time": 8.443,
"calls": 611,
"data":[
{
"name":"makeArray()",
"calls":1,
"percent":23.58,
"ownTime":1.991,
"time":1.991,
"avgTime":1.991,
"minTime":1.991,
"maxTime":1.991,
"fileName":"jquery.js (line 2059)"
},
// etc.
]}
fireunit.getProfile();
http://ejohn.org/blog/function-call-profiling/
Complexity Analysis! Analyze complexity rather than raw time
! jQuery Call Count Pro$ler "uses FireUnit#
Method Calls Big-O
.addClass("test"); 542 6n
.addClass("test"); 592 6n
.removeClass("test"); 754 8n
.removeClass("test"); 610 6n
.css("color", "red"); 495 5n
.css({color: "red", border: "1px solid red"});
887 9n
.remove(); 23772 2n+n2
.append("<p>test</p>"); 307 3n
Complexity Analysis! Reducing call count helps to reduce
complexity
! Results for 1.3.3:
Method Calls Big-O
.remove(); 298 3n
.html("<p>test</p>"); 507 5n
.empty(); 200 2n
http://ejohn.org/blog/function-call-profiling/
Testing
Test Suites! Automated testing
! jQuery, Prototype, Dojo, YUI all have their own test suites
QUnit! jQuery&s Test Suite
! Nice and simple! Works well for asynchronous tests, too.
qUnit Usage! test("a basic test example", function() {
ok( true, "this test is fine" );
var value = "hello";
equals( "hello", value, "We expect value to be hello" );
});
module("Module A");
test("first test within module", function() {
ok( true, "all pass" );
});
test("second test within module", function() {
ok( true, "all pass" );
});
module("Module B");
test("some other test", function() {
expect(1);
ok( true, "well" );
});
qUnit Output
Choose Your Browsers
Cost / Bene$t
IE 7 IE 6 FF 3 Safari 3 Opera 9.5
Cost Benefit
Draw a line in the sand.
Graded Support
Yahoo Browser Compatibility
Browser Support Grid
IE Firefox Safari Opera Chrome
Previous 6.0 2.0 3.0 9.5
Current 7.0 3.0 3.2 9.6 1.0
Next 8.0 3.1 4.0 10.0 2.0
jQuery Browser Support
Browser Support Grid
IE Firefox Safari Opera Chrome
Previous 6.0 2.0 3.0 9.5
Current 7.0 3.0 3.2 9.6 1.0
Next 8.0 3.1 4.0 10.0 2.0
jQuery 1.3 Browser Support
The Scaling Problem! The Problem:
! jQuery has 6 test suites! Run in 11 browsers! "Not even including multiple platforms!#
! All need to be run for every commit, patch, and plugin.
! JavaScript testing doesn&t scale well.
Distributed Testing! Hub server
! Clients connect and help run tests
! A simple JavaScript client that can be run in all browsers! Including mobile browsers!
!TestSwarm
TestSwarm
FF 3
FF 3
FF 3.5 FF 3.5 FF 3.5IE 6
IE 6
IE 6
IE 7
IE 7
Op 9
Test Suite Test Suite Test Suite
Manual Testing! Push tests to users who follow pre%de$ned
steps
! Answer 'Yes&/&No& questions which are pushed back to the server.
! An e!ective way to distribute manual test load to dozens of clients.
TestSwarm.com! Incentives for top testers "t%shirts, books#
! Will be opening for testing at the end of the month
! Help your favorite JavaScript library become better tested!
! http://testswarm.com
Q&APlease come up to the microphones!