non-blocking java script

Post on 25-Jan-2015

2.937 Views

Category:

Documents

1 Downloads

Preview:

Click to see full reader

DESCRIPTION

 

TRANSCRIPT

Non-Blocking JavaScriptDmitriy Yakubovskiy

Параллельные загрузки

Потоки по браузерам *

Firefox 3+ 6 потоков

Chrome 6 потоков

Safari 3-4 4 потока

Safari 56 потоков

Opera 12 6 потоков

IE 6-7 2 потока

IE 8-96 потоков

IE 108 потоков

* - число параллельных соединений к одному хосту

Процесс отрисовки

Исходный HTML DOM дерево Дерево отрисовки

DOMContentLoaded

- событие срабатывает при загрузке документа, кроме IE<9

- ждет css, если после него идет скрипт

- ждёт загрузки и выполнения скриптов (кроме скриптов с

async/defer, если есть поддержка и динамических)

- в FF/Chrome формы автозаполняются по

DOMContentLoaded

- интерфейсы обычно инициализируются по

DOMContentLoaded

DOMContentLoaded (Firefox)

Скрипты на странице*

Во время загрузки

Во время выполнения

- блокируется отрисовка страницы- блокируют вообще все загрузки (IE<8, Opera<15)- блокируют все загрузки, кроме стилей и скриптов (IE8, FF, Chrome, Safari)- остальные загрузки не блокируются (IE>8)

- ждет пока загрузятся предшествующие css файлы- блокируют вообще всё

* - распространяется на скрипты со всех хостов

Скрипты в HEAD

IE6-7

Скрипты в HEAD

IE8

Скрипты в HEAD

IE9

Скрипты в HEAD

Сhrome / Safari / FF

Скрипты в конце BODY

Chrome

- не блокируется рендеринг страницы- не блокируются загрузки предыдущих ресурсов- страница доступна до инициализации скриптов

Заглушки интерфейсов

<link rel="stylesheet" type="text/css" href="styles.css" />

<!--[if lte IE 8]>

<link rel="stylesheet" type="text/css" href="ie.css">

<![endif]-->

Conditional Comments (IE)

Conditional Comments (IE)

<!--[if IE]><![endif]-->

<link rel="stylesheet" type="text/css" href="styles.css" />

<!--[if lte IE 8]>

<link rel="stylesheet" type="text/css" href="ie.css">

<![endif]-->

Не блокирующие скрипты

- document.write- script in iframe- script defer- script async- XMLHttpRequest Eval- XMLHttpRequest Injection- Script DOM

document.write

IE6

document.write('<scr'+'ipt src="jquery.js"></scr'+'ipt>');

document.write('<scr'+'ipt src="scripts.js"></scr'+'ipt>');

- не блокирует другие скрипты- сохраняет порядок выполнения- блокирует рендеринг, загрузку css/img- актуально только для IE<8, Opera<15

script in iframe

- не блокирует рендеринг / загрузки- необходимо вносить изменения в скрипты- ограничение по домену

<iframe src='script.html' id="f1"></iframe>

<iframe src='script2.html' id="f2"></iframe>

script defer- по стандарту только для внешних скриптов- не блокирует рендеринг / загрузки- выполнение после рендеринга страницы- сохраняется порядок выполнения (кроме IE<10)- IE4+, FF3.1+, Chrome 8+, Safari 5.1+, Opera 15+<script src="jquery.js" defer></script>

<script src="scripts.js" defer></script>

script async- по стандарту только для внешних скриптов- не блокирует рендеринг / загрузки- выполнение сразу после загрузки- не сохраняется порядок выполнения- IE10+, FF3.6+, Chrome 8+, Safari 5.1+, Opera 15+<script src="script1.js" async></script>

<script src="script2.js" async></script>

XMLHttpRequest Eval

var xhr = getXmlHttp();

xhr.open("GET", "script.js", true);

xhr.onreadystatechange = function() {

if (xhr.readyState == 4 && xhr.status == 200) {

eval.call(window, xhr.responseText);

}

}

xhr.send(null);

- не блокирует рендеринг / загрузки- не сохраняется порядок выполнения- ограничение по домену- нет индикации загрузки

XMLHttpRequest Injection- не блокирует рендеринг / загрузки- не сохраняется порядок выполнения- ограничение по домену- нет индикации загрузкиvar xhr = getXmlHttp();xhr.open("GET", "script.js", true);xhr.onreadystatechange = function() { if (xhr.readyState == 4 && xhr.status == 200) { var s=document.createElement('script'); document.getElementsByTagName('head')[0] .appendChild(s); s.text = xhr.responseText; }} xhr.send(null);

Script DOM

var script = document.createElement('script');

script.type = 'text/javascript';

script.async = true;

script.src = 'app.js';

document.getElementsByTagName('head')[0]

.appendChild(script);

- не блокирует рендеринг / загрузки- не сохраняется порядок выполнения, кроме Opera<15- async:true для Firefox 3.6, чтобы не сохранять порядок- нет ограничений на домен

Script DOM + async:false

- не блокирует рендеринг / загрузки- сохраняется порядок выполнения (кроме браузеров, которые не поддерживают async, но не FF<3.6 и Opera)- нет ограничений на домен

var script = document.createElement('script');

script.type = 'text/javascript';

script.async = false;

script.src = 'app.js';

document.getElementsByTagName('head')[0]

.appendChild(script);

Script DOM + onreadystatechange

- не блокирует рендеринг / загрузки- позволяет гибко управлять загрузкой / выполнением- нет ограничений на домен- только IE6+

var js = document.createElement('script');

js.onreadystatechange = function() {

if (js.readyState == 'loaded') {

document.body.appendChild(js); // execution

}

};

js.src = 'app.js';

Порядок загрузки не важен

Цель:

- Загрузить скрипты параллельно- Выполнить сразу после загрузки- Не блокировать рендеринг- Не блокировать загрузку других ресурсов- Кроссбраузерное решение

Решение: Script DOM

Порядок загрузки важен

Цель:

- Загрузить скрипты параллельно- Выполнить последовательно- Не блокировать рендеринг- Не блокировать загрузку других ресурсов- Кроссбраузерное решение

Решение: Script DOM + async:false / onreadystatechange для IE / document.write для остальных браузеров

Техники связывания

- window onload- timer- script onload

- callback (m)- degrading script tags (m)

m - требует модификации скриптов

Техники связывания

<script type="text/javascript">

function init() {

...

App.start();

...

}

init();

</script>

<script type="text/javascript" src="app.js"></script>

window onload

if ( window.addEventListener ) {

window.addEventListener("load", init, false);

}

else if ( window.attachEvent ) {

window.attachEvent("onload", init);

}

- просто в реализации- инициализация срабатывает слишком поздно

timer

function timer(interval) { if ( typeof(jQuery) === "undefined" ) { setTimeout(timer, interval); } else { init(); }}timer(300);

- просто в реализации- лишние расходы ресурсов на выполнение скрипта- задержка при слишком большом интервале

script onload

js.onload = function() { if ( !js.done ) { js.done = true; init(); }};js.onreadystatechange = function() { if ( !js.done && js.readyState.match(/loaded|complete/) ) { js.done = true; init(); }};

- выполнение инлайн скрипта максимально быстро- немного сложнее в реализации

callback (m)

- выполнение инлайн скрипта максимально быстро- вызов init() в конце app.js- не гибкое решение- требует модификации скриптов

function init() { ... }

var js = document.createElement('script');

js.src = "app.js"; document.getElementsByTagName('head')

[0].appendChild(js);

degrading script tags (m)

function init() { ... }var js = document.createElement('script');js.src = "app.js";js.text = "init();"; document.getElementsByTagName('head')[0].appendChild(js);

- гибкое решение- требует модификации скриптов

inline script

<script type="text/javascript" src="app.js"> init();</script>

degrading script tags (m)

var fs = document.getElementsByTagName("script");

var len = fs.length;

while ( len ) {

var s = fs[len-1];

if ( s.src.indexOf('app.js') != -1 ) {

eval( s.innerHTML );

break;

}

len--;

}

app.js

Загрузчики

- $script.js- YepNope.js- Control.js- LAB.js- Head.js- Load.js- Require.js

Как будем загружать сам загрузчик?

Загрузка виджетов

● Добавление через DOM

● Связывание через onload/onreadystatechange

● document.write()○ Делаем свой document.write()○ Выносим виджет в отдельный

невидимый элемент○ Загружаем в скрытый iframe,

по onload копируем на страницу

Загрузка виджетов(function(d, s) {

var js, fjs = d.getElementsByTagName(s)[0],

load = function(url, id) {

if (d.getElementById(id)) {return;}

js = d.createElement(s);

js.src = url;

js.id = id;

fjs.parentNode.insertBefore(js, fjs);

};

load('widget1.js', 'fbjssdk');

load('widget2.js', 'gplus1js');

load('widget3.js', 'tweetjs');

}(document, 'script'));

Преимущества подхода

Страница не виснет из-за сторонних виджетов

Управление виджетами из одного места

Гарантия подключения узла всего один раз (ID)

Постзагрузка виджетов

Постзагрузка виджетов

Полезные материалы

Ресурсыwww.browserscope.orgwww.stevesouders.com

КнигаSteve Souders - Even Faster Web Sites

Таблица сравнения загрузчиковhttps://spreadsheets.google.com/a/sysiq.com/lv?key=tDdcrv9wNQRCNCRCflWxhYQ

● WebPageTest Online (www.webpagetest.org)

● Webkit Developer Toolbar (Timeline Tab)

● Firebug for FF (YSlow add-on, Net Tab)

● Fiddler (Web Debugging Proxy)

● DynaTrace Ajax Edition

● Sloppy (proxy server)

Инструменты

Вопросы?

Задавайте умные вопросы.

Получайте умные ответы.

Dmitriy Yakubovskiyd.iakubovskiy@sysiq.com

top related