Upload
caelum
View
3.475
Download
0
Embed Size (px)
DESCRIPTION
Techniques for fast and modular JS loading. Talk presented at JSConf Brazil 2013 in Fortaleza by Sérgio Lopes
Citation preview
ALL YOU NEED TO KNOW ABOUTJAVASCRIPTLOADING AND EXECUTIONIN THE BROWSER
<SCRIPT language="JavaScript">//<![CDATA[alert('
');//]]></SCRIPT>
@sergio_caelumsergiolopes.org
<script src="/js/main.js"></script>
THE END
THE END?
HOW BROWSERS LOAD AND EXECUTE JS
disclaimer
HOW BROWSERS LOAD AND EXECUTE JS
<html><head> <script src="main.js"></script></head><body> ...</body></html>
JS BLOCKS RENDERING
JS BLOCKS RENDERING
JS BLOCKS RENDERINGNETWORK LATENCY
PARSING TIMEEXECUTION TIME
AVAILABILITY (SPOF)
PUT JS AT BOTTOM
<html><head> <script src="main.js"></script></head><body> ...
</body></html>
<html><head>
</head><body> ... <script src="main.js"></script></body></html>
DEFER
<html><head> <script src="main.js" defer></script></head><body> ...</body></html>
<html><head> <script src="main.js" defer></script> <script src="other.js" defer></script></head><body> ...</body></html>
PUT JS AT BOTTOMPLUS: NO NEED FOR $(document).ready(..) ANYMORE
MULTIPLE SCRIPTS
<script src="jquery.js"></script><script src="jquery.plugin.js"></script><script src="application.js"></script>...
LATENCY
SCRIPT CONCATENATION
SCRIPT CONCATENATION1 SCRIPT? 2 SCRIPTs?
SEQUENTIAL EXECUTION
ASYNC LOADING
var js = document.createElement('script');js.src = 'script.js';document.head.appendChild(js);
<script src="main.js" async></script><script src="other.js" async></script>
<html><head> <script src="main.js" async></script> <script src="other.js" async></script></head><body>
</body></html>
EXECUTION ORDER?
SEPARATE DOWNLOAD FROM EXECUTION
<script src="main.js" type="bla"></script>
<script src="main.js"></script>
<script src="main.js"></script>
/* alert('Everything commented out'); ... */
<script src="main.js"></script>
/* alert('Everything commented out'); ... */
eval(js_code_inside_comments);
new Image().src = 'script.js';
new Image().src = 'script.js';
<script src="script.js"></script>
var ajax = new XMLHttpRequest();
ajax.onreadystatechange = function(js){ if (ajax.readyState == 4) // execute js in order};
ajax.open('script.js');ajax.send();
Ajax
var js = document.createElement('script');js.src = 'script.js';
IE
var js = document.createElement('script');
js.src = 'script.js';
IE
js.onreadystatechange = function(){ if (js.readyState == 'loaded') document.head.appendChild(js);};
var js = document.createElement('script');js.preload = true;js.onpreload = function(){ // ...};
js.src = 'script.js';
preload=true
var js = document.createElement('script');js.async = false;js.src = 'script.js';document.head.appendChild(js);
async=false
SCRIPT LOADERS
$LAB.script('jquery.js').wait() .script('plugin1.js') .script('plugin2.js') .script('plugin3.js').wait() .script('application.js');
LABjs
DISCOVERABILITY
<script src="labjs.js"></script>
<script>$LAB.script('jquery.js').wait() .script('plugin1.js') .script('plugin2.js') .script('plugin3.js').wait() .script('application.js');</script>
<script>/* inline ~2KB do LABjs */</script>
<script>$LAB.script('jquery.js').wait() .script('plugin1.js') .script('plugin2.js') .script('plugin3.js').wait() .script('application.js');</script>
LOOK AHEAD PRE-PARSER
<link rel="prefetch" href="script.js">
<link rel="subresource" href="script.js">
<link rel="subresource prefetch" href="script.js">
ASYNC EXECUTION
<script src="script1.js" async></script><script src="script2.js" async></script><script src="script3.js" async></script>
DEPENDENCIES?
order != dependency
<script src="script1.js"></script><script src="script2.js"></script><script src="script3.js"></script><script src="script4.js"></script><script src="script5.js"></script>
AMDASYNCHRONOUS MODULE DEFINITION
* OR SOMETHING SIMILAR
$('#panel').fadein();
define('app', ['jquery'], function($) {
}); $('#panel').fadein();
var jQuery = // ...
var jQuery = // ... function() {
return jQuery;}
define('jquery',[],
);
var jQuery = // ... function() {
return jQuery;}
BETTER CODE
ASYNC DEPENDENCY EXECUTION
Require.js
<script src="require.js" data-main= "myapp"></script>
<script src="require.js" data-main= "myapp"></script>
myapp.js
<script src="require.js" data-main= "myapp"></script>
myapp.js
mymodel.js mycontroller.js
<script src="require.js" data-main= "myapp"></script>
myapp.js
mymodel.js mycontroller.js
util.js plugin1.js plugin2.js
<script src="require.js" data-main= "myapp"></script>
myapp.js
mymodel.js mycontroller.js
jquery.js
util.js plugin1.js plugin2.js
BUILD
r.js + almond
r.js + almondr.js -o baseUrl=. name=almond include=main out=all.js wrap=true
<script src="all.js"></script>
myapp.js
mymodel.js mycontroller.js
jquery.js
util.js plugin1.js plugin2.js
all.js
almond.js
myapp.js
mymodel.js mycontroller.js
jquery.js
util.js plugin1.js plugin2.js
almond.jsbase.js
mypage.js
<script src="base.js"></script><script src="mypage.js"></script>
<script>/* 250b AMD define */</script>
<script src="base.js" async></script><script src="modules.js" async></script><script src="more.js" async></script>
FUTURE
TEST: 200 JS modules, ~13KB each
#1200 .js files + 1 HTML file<script async>HTTP
TEST: 200 JS modules, ~13KB each
#21 .js file + 1 HTML file<script async>HTTP
TEST: 200 JS modules, ~13KB each
#3200 .js files + 1 HTML file<script async>SPDY
200 files
1 file
0 12500 25000 37500 50000
HTTP:
200 files
1 file
200 files
1 file
0 12500 25000 37500 50000
HTTP:
SPDY:
SPDY & HTTP 2.0
FUTURE #2
module utils { var local = 0; export var exposed = "Public API";}
Modules
Modules
module main { import exposed from utils; console.log(exposed);}
ES-HARMONY
<script>deferasync
SCRIPT LOADERSprefetch / subresource
AMDrequire.js / r.js / almond
SPDY & HTTP 2ES-HARMONY MODULES *
ALL YOU NEED TO KNOW ABOUTJAVASCRIPTLOADING AND EXECUTIONIN THE BROWSER
<SCRIPT language="JavaScript">//<![CDATA[alert('
');//]]></SCRIPT>
THANK YOUsergiolopes.org
@sergio_caelum
<SCRIPT language="JavaScript">//<![CDATA[alert('
');//]]></SCRIPT>