Статьи

Перевод: Николай Мациевский aka sunnybear
Опубликована: 9 марта 2008

Высокопроизводительные AJAX-приложения

Примечание: ниже перевод презентации "High Performance Ajax Applications", подготовленной ведущим специалистом из Yahoo (а теперь уже из Apple) Julien Lecomte. В ней автор освещает некоторые аспекты оптимизации как JavaScript-приложений, так и веб-сайтов вообще. В целом, советов много, и почти все, действительно, по делу. Однако, встречается и откровенная реклама Yahoo :) Мои комментарии далее курсивом.

Часть 1. Разработка для высокой производительности

Планируем и проектируем для высокой производительности

  • Ориентируемся на производительность с самого первого дня
  • Тесно работаем с дизайнерами и менеджерами продукта
  • Понимаем рациональность дизайна
  • Объясняем компромиссы между дизайном и производительностью
  • Предлагаем альтернативы и показываем, что еще возможно (на уровне прототипа)
  • Пробуем силы в реализации нетривиального дизайна (нельзя сразу говорит «нет»)
  • Помогаем упростить дизайн и взаимодействие с пользователем (добиваемся компромисса)

Разрабатываем высокопроизводительные системы: несколько базовых правил

  • Лучше меньше — да лучше
    • Не делайте ничего ненужного.
    • Не делайте ничего, пока это не станет по-настоящему необходимым.
  • Нарушайте правила
    • Добивайтесь компромиссов и нарушайте сложившиеся методики (best practices), но только в качестве последнего средства!
  • Работайте над улучшением ощущаемой производительности
    • Пользователи могут немного подождать, если:
      • их уведомили соответствующим образом о том, что операция задерживается.
      • Пользовательский интерфейс постоянно реагирует на действия пользователя.
    • Можно схитрить, если все операции проделать уже после обновления интерфейса пользователя.

Измеряемая производительность

  • Тестируйте производительность, используя окружение, аналогичное пользовательскому
  • Отлаживайте ваш код в процессе разработки
  • Автоматизируйте функциональное тестирование и проверку производительности
  • Сохраняйте историю изменений, как быстро функционируют различные возможности
  • Может быть, стоит оставить некоторое (небольшое) количество отладочного кода на «боевом» сервере

Часть 2. Высокопроизводительная загрузка страницы

Способы ускорения загрузки Вашего сайта от Yahoo!

Веб-страница работает в 3 иногда перекрывающихся состояниях:

  1. загрузка
  2. отрисовка
  3. исполнение

Следующие правила покрывают, в основном, первое состояние.

  • Уменьшите количество HTTP-запросов
  • Используйте CDN
  • Используйте HTTP-заголовок Expires
  • Сжимайте компоненты страницы
  • Помещайте CSS в начале страницы
  • Помещайте скрипты в конец
  • Избегайте CSS-выражений (expressions)
  • Выносите javascript и CSS во внешние файлы
  • Уменьшайте количество DNS-запросов
  • Минимизируйте Javascript
  • Избегайте редиректов
  • Уберите повторяющиеся скрипты
  • Настройте ETag'и
  • Делайте AJAX кэшируемым

Для более подробной информации можно ознакомиться с переводом этой статьи на webo.in.

Оптимизация активов

Уменьшайте размер кода, который не минимизируется

  • Загрузка и анализ HTML, CSS и JavaScript-кода ресурсоемки.
  • Будьте кратки и пишите меньше кода.
  • Используйте JavaScript-библиотеки по назначению.
  • Может быть, стоит разделить ваши большие JavaScript-файлы на несколько более маленьких (пакетов), если анализ и исполнение скриптов занимает слишком много времени (ошибка Firefox #313967)
  • Загружайте код (HTML, CSS и JavaScript) по требованию (a.k.a «ленивая загрузка» или ненавязчивый JavaScript)
    • Ознакомьтесь с http://ajaxpatterns.org/On-Demand_Javascript
    • Используйте загрузчик YUI
    • Рассмотрите систему пакетов в Dojo
    • Рассмотрите систему импортов в JSAN

Оптимизируем начальную загрузку (1/4). Общие советы...

  • Лучше создавать первоначальный вид страницы прямо на сервере:
    • Избегайте добавления к странице лишнего объема
    • Вам по-прежнему придется прикреплять обработчики событий, как только будет готово DOM-дерево
  • Закрывайте HTML-теги для ускорения анализа страницы:
  • Может быть, стоит сбрасывать буфер вывода для Apache как можно быстрее:
    • Загрузка внешних CSS-файлов (должны быть в самом верху страницы!) может начинаться сразу после объявления тега <head>.
    • Однако, это может не повлиять на скорость отображения браузерами, ибо они, скорее всего, буферизируют данные перед их отображением.
  • Загружайте только необходимые ресурсы / загружайте ресурсы с задержкой или по запросу
    • Используйте YUI Image Loader

Оптимизируем начальную загрузку (2/4). Не всегда стоит ждать onload...

  • Большинство DOM-операций может быть выполнено перед тем, как сработает событие onload.
  • Если вы обладаете полным контролем нам тем, где можно разместить вызовы скриптов, стоит инициализировать весь ваш код в теге <script>, расположенном прямо перед закрывающим тегом </body>.
  • Также можно использовать метод onDOMReady в утилите YUI Event:
    YAHOO.util.Event.onDOMReady(function () {
        // Выполняем какие-нибудь действия...
        // например, прикрепляем обработчики событий.
    });

Оптимизируем начальную загрузку (3/4). Загрузка скриптов напоследок

  • Если ваш сайт хорошо спроектирован, то должен полностью работать и без включенного JavaScript.
  • Следовательно, вы можете загружать все скрипты с некоторой задержкой.
  • Следуя этому принципу, можно загрузить все остальные ресурсы (файлы стилей, изображения и т.д.) в первую очередь
  • Это (визуально) увеличит скорость загрузки сайта
  • Прямо перед закрывающим тегом </body> добавьте следующее:
    <script>
    
    window.onload = function () {
        var script = document.createElement("script");
        script.src = ...;
        document.body.appendChild(script);
    };
    
    </script>

Оптимизируем начальную загрузку (4/4). Условная предзагрузка

  • Предзагрузка ресурсов (JavaScript, CSS, изображений и т.д.) потенциально улучшит удобство для пользователя.
  • Однако, стоит хорошо задуматься о том, что и когда подгружать: предзагрузка может и ухудшить удобство использования сайта...
  • http://www.sitepoint.com/article/web-site-optimization-steps/3
  • Оценить демонстрационную версию можно по адресу: http://search.yahoo.com/

Часть 3. Высокопроизводительный JavaScript

Уменьшаем число запросов для разрешения ссылок: цепочка областей видимости (1/2)

  • Разрешение (look-up) ссылки выполнятся каждый раз, когда запрашивается переменная.
  • Переменные разрешаются в обратном порядке: от более частной области видимости к более общей.
var g = 7;
function f(a) {
    var v = 8;
    x = v + a + g;
}
f(6);

Уменьшаем число запросов для разрешения ссылок: цепочка областей видимости (2/2)

  • Поэтому старайтесь использовать переменные максимально близко к области их объявления (с помощью ключевого слова var) и избегайте использования глобальных переменных любой ценой.
  • Никогда не используйте ключевое слово with, так как оно не дает компилятору генерировать код для быстрого доступа к локальным переменным (ему приходится сначала пробежаться по цепочке прототипа объекта, затем по цепочке вышестоящей области видимости и т.д.)
  • Кешируйте ресурсоемкие вызовы в локальные переменные:
    // так хуже	
    var arr = ...;
    var globalVar = 0;
    (function () {
        var i;
        for (i = 0; i < arr.length; i++) {
        globalVar++;
    }
    })();
    // так лучше
    var arr = ...;
    var globalVar = 0;
    (function () {
        var i, l, localVar;
        l = arr.length;
        localVar = globalVar;
        for (i = 0; i < l; i++) {
    	localVar++;
        }
        globalVar = localVar;
    })();

Уменьшаем число запросов для разрешения ссылок: цепочка прототипов

  • Доступ к членам объекта, определенным в нем самом, примерно на 25% быстрее, чем доступ к любому члену в цепочке прототипов.
  • Чем больше цепочка прототипов (и путь до вызываемого свойства или метода), тем медленнее работает скрипт.
function A () {}
A.prototype.prop1 = ...;

function B () {
    this.prop2 = ...;
} B.prototype = new A();
var b = new B();

Оптимизируем вызовы объектов

  • Если вам требуется создать много объектов, стоит рассмотреть добавление их к прототипу родительского объекта вместо создания индивидуальных свойств в текущем объекте (для прототипа свойства будут созданы только один раз, а затем этот прототип будет использоваться для создания новых объектов).
  • Это также уменьшит объем выделяемой памяти.
  • Однако, это замедлит обращение к членам объекта (ведь придется просматривать цепочку прототипов).
// быстрее для создания большого количества одинаковых объектов
function Foo () {...}
Foo.prototype.bar = function () {...};
// быстрее для обращения к свойствам объектов
function Foo () {
    this.bar = function () {...};
}

Не используейте eval!

  • Строка, которая передается eval (и всем родственным ему методам: конструктору Function, функциям setTimeout и setInterval), должна быть скомилирована и выполнена. Это очень медленно!
  • Никогда не передавайте строку в вызовы функций setTimeout и setInterval. Вместо это используйте анонимную функция, например:
    setTimeout(function () {    
        // код, который нужно выполнить с задержкой
    }, 50);
  • Никогда не используйте eval и конструктор Function (кроме, может быть, некоторых очень редких случаев, и только в тех блоках, где производительность не является критичной, т.е. расширяемость или логичность модели, например, будут важнее, чем производительность).

Оптимизируем объединение строк

  • В Internet Explorer (JScript) объединение двух строк порождает создание новой строки, в которую обе они копируются:
    var s = "xxx" + "yyy";
    s += "zzz";
  • Следовательно, для Internet Explorer будет значительно быстрее добавлять строки в массив, а затем, используя, Array.join, объединить (не используйте это для простых объединений, работает сильно медленее!)
    // медленнее
    var i, s = "";
    for (i = 0; i < 10000; i++) {
        s += "x";
    }
    // быстрее
    var i, s = [];
    for (i = 0; i < 10000; i++) {
        s[i] = "x";
    }
    s = s.join("");
  • Другие JavaScript-движки (WebKit, SpiderMonkey) уже оптимизированы, чтобы использовать realloc + memcpy во всех возможных случаях объединения строк.
  • Используйте YUI Compressor!

Оптимизируйте регулярные выражения

  • Не используйте конструктор RegExp, если вы не собираетесь создавать регулярное выражение «на лету». Вместо этого используйте постоянные регулярные выражения (regular expression literals).
  • Используйте метод test, если вам нужно просто проверить, соответствует ли строка шаблону (метод exec немного более ресурсоемкий)
    if (/loaded|complete/.test(document.readyState)) {...}
  • Используйте нефиксирующие (non-capturing) группы (?:...)
  • Придерживайтесь простых шаблонов. Стоить пересмотреть ваши регулярные выражения, если они выглядит примерно так...
    (?:(?:\r\n)?[\t])*(?:(?:(?:[^()<>@,;:\\".\[\]\000-\031]+
    (?:(?:(?:\r\n)?[\t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:
    [^\"\r\\]|\\.|(?:(?:\r\n)?[\t]))*"(?:(?:\r\n)?[\t])*)(?:
    \.(?:(?:\r\n)?[\t])*(?:[^()<>@,;:\\".\[\]\000-\031]+(?:(
    ?:(?:\r\n)?[\t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"
    \r\\]|\\.|(?:(?:\r\n)?[\t]))*"(?:(?:\r\n)?[\t])*))*@(?:(
    ?:\r\n)?[\t])*(?:[^()<>@,;:\\".\[\]\000-\031]+(?:(?:(?:\
    r\n)?[\t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]
    |\\.)*\](?:(?:\r\n)?[\t])*)(?:\.(?:(?:\r\n)?[\t])*(?:[^(
    )<>@,;:\\".\[\]\000-\031]+(?:(?:(?:\r\n)?[\t])+|\Z|(?=[\
    ["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?
    [\t])*))*|(?:[^()<>@,;:\\".\[\]\000-\031]+(?:(?:(?:\r\n)
    ?[\t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|
    (?:(?:\r\n)?[\t]))*"(?:(?:\r\n)?[\t])*)*\<(?:(?:\r\n)?[\
    t])*(?:@(?:[^()<>@,;:\\".\[\]\000-\031]+(?:(?:(?:\r\n)?[
    \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*
    \](?:(?:\r\n)?[\t])*)(?:\.(?:(?:\r\n)?[\t])*(?:[^()<>@,;
    :\\".\[\]\000-\031]+(?:(?:(?:\r\n)?[\t])+|\Z|(?=[\["()<>
    @,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[\t])*
    ))*(?:,@(?:(?:\r\n)?[\t]))

Кеширование

  • Кеширование оправдано в следующих случаях:
    • Высокие издержки (CPU или сетевые задержки), связанные с получением значения
    • Значение будет прочитано много раз
    • И не будет часто меняться!
  • Увеличивает потребление памяти -> нужно найти компромисс
  • Схемы хранения в памяти:

    Модульный шаблон

    var fn = (function () {
        var b = false, v;
        return function () {
    	if (!b) {
    	    v = ...;
    	    b = true;
    	}
    	return v;
        };
    })();

    Сохранение значение в объекте функции

    function fn () {
        if (!fn.b) {
            fn.v = ...;
    	fn.b = true;
        }
        return fn.v;
    }

    «Ленивое» объявление функции

    var fn = function () {			    
        var v = ...;
        return (fn = function () {
    	return v;
        })();
    };

Что делать с JavaScript-процессами, которые долго выполняются (1/2)

  • В время работы процесса, который долго исполняется, весь UI браузера «замораживается»
  • Следовательно, для обеспечения более-менее комфортного восприятия со стороны пользователя, нужно убедиться, чтобы каждый JavaScript-поток не исполнялся более ~ 300 мс (самое большое).
  • Можно разбить длительные процесс на ряд более маленьких порций работы и объединить их в цепочку, используя setTimeout.
  • Также можно обрабатывать все данные на стороне сервера.
  • Больше информации доступно по адресу http://www.julienlecomte.net/blog/2007/10/28 (перевод)
  • Демонстрационная версия

Что делать с JavaScript-процессами, которые долго выполняются (2/2)

function doSomething (callbackFn) {

    // Здесь инициализируем данные...

    (function () {

	// Делаем некоторую работу...

	if (termination condition) {
	    // мы закончили
	    callbackFn();
	} else {
	    // обрабатываем следующую порцию
	    setTimeout(arguments.callee, 0);
	}

    })();

}

Разные советы (1/2)

  • Элементарные операции часто быстрее, чем вызовы соответствующих функций:
    var a = 1, b = 2, c;
    // медленнее
    c = Math.min(a, b);
    // быстрее
    c = a < b ? a : b;
    // медленнее
    myArray.push(value);
    // быстрее
    myArray[myArray.length] = value;
    // еще быстрее
    myArray[idx++] = value;
  • По возможности избегайте использования try...catch в тех частях, в которых критична производительность:
    // медленнее
    var i;
    for (i = 0; i < 100000; i++) {
        try {
            ...
        } catch (e) {
    	...
        }
    
    }
    // быстрее
    var i;
    try {
        for (i = 0; i < 100000; i++) {
            ...
        }
    } catch (e) {
        ...
    }

Разные советы (2/2)

  • По возможности избегайте использования for...in в тех частях, в которых критична производительность:
    // медленнее
    var key, value;
    for (key in myArray) {
        value = myArray[key];
        ...
    }
    // быстрее	
    var i, value, length = myArray.length;
    for (i = 0; i < length; i++) {
        value = myArray[i];
        ...
    }
  • Делайте ветвление, по возможности, на самом высоком уровне (относительно условия ветвления):
    // медленнее	
    function fn () {
        if (...) {
            ...
        } else {
    	...
        }
    }
    // быстрее
    var fn;
    if (...) {
        fn = function () {...};
    } else {
        fn = function () {...};
    }

Часть 4. Высокопроизводительный динамический HTML

Изменение дерева документа при помощи innerHTML

var i, j, el, table, tbody, row, cell;
el = document.createElement("div");
document.body.appendChild(el);
table = document.createElement("table");
el.appendChild(table);
tbody = document.createElement("tbody");
table.appendChild(tbody);
for (i = 0; i < 1000; i++) {
    row = document.createElement("tr");
    for (j = 0; j < 5; j++) {
	cell = document.createElement("td");
	row.appendChild(cell);
    }
    tbody.appendChild(row);
}

(сильно быстрее во всех браузерах класса А)

var i, j, el, idx, html;
idx = 0;
html = [];
html[idx++] = "<table>";
for (i = 0; i < 1000; i++) {
    html[idx++] = "<tr>";
    for (j = 0; j < 5; j++) {
	html[idx++] = "<td></td>";
    }
    html[idx++] = "</tr>";
}
html[idx++] = "</table>";
el = document.createElement("div");
document.body.appendChild(el);
el.innerHTML = html.join("");

Замечание: прочитайте http://www.julienlecomte.net/blog/2007/12/38/ (перевод)

Изменение дерева документа при помощи cloneNode

var i, j, el, table, tbody, row, cell;
el = document.createElement("div");
document.body.appendChild(el);
table = document.createElement("table");
el.appendChild(table);
tbody = document.createElement("tbody");
table.appendChild(tbody);
for (i = 0; i < 1000; i++) {
    row = document.createElement("tr");
    for (j = 0; j < 5; j++) {
	cell = document.createElement("td");
	row.appendChild(cell);
    }
    tbody.appendChild(row);
}

(быстрее по всех браузерах класса А, иногда значительно быстрее)

var i, el, table, tbody, template, row, cell;
el = document.createElement("div");
document.body.appendChild(el);
table = document.createElement("table");
el.appendChild(table);
tbody = document.createElement("tbody");
table.appendChild(tbody);
template = document.createElement("tr");
for (i = 0; i < 5; i++) {
    cell = document.createElement("td");
    template.appendChild(cell);
}
for (i = 0; i < 1000; i++) {
    row = template.cloneNode(true);
    tbody.appendChild(row);
}

Замечание: расширенные свойства (expando properties) и прикрепленные обработчики событий будут утеряны!

Изменение дерева документа при помощи DocumentFragment

  • DocumentFragment (DOM Level 1 Core) является облегченным вариантом Document.
  • Он поддерживает только ограниченное число обычных DOM-методов и свойств.
  • Реализация в IE интерфейса для DocumentFragment не соответствует спецификации W3C и возвращает обычный объект Document.
var i, j, el, table, tbody, row, cell, docFragment;
docFragment = document.createDocumentFragment();
el = document.createElement("div");
docFragment.appendChild(el);
table = document.createElement("table");
el.appendChild(table);
tbody = document.createElement("tbody");
table.appendChild(tbody);
for (i = 0; i < 1000; i++) {
    ...
}
document.body.appendChild(docFragment);

Уменьшайте число обработчиков событий (1/2)

  • Прикрепление обработчика событий к сотням элементов весь ресурсоемко
  • Наращивание количества обработчиков событий чревато потенциальными утечками памяти
  • Решение: использовать event delegation, технику, базирующуюся на event bubbling
<div id="container">
    <ul>
	<li id="li-1">List Item 1</li>
	<li id="li-2">List Item 2</li>
	<li id="li-3">List Item 3</li>
	<li id="li-4">List Item 4</li>
	<li id="li-5">List Item 5</li>
	...
    </ul>
</div>

Уменьшайте число обработчиков событий (2/2)

YAHOO.util.Event.addListener("container", "click", function (e) {			    
    var el = YAHOO.util.Event.getTarget(e);
    while (el.id !== "container") {
	if (el.nodeName.toUpperCase() === "LI") {
	    // Что-нибудь делаем...
	    break;
	} else {
	    el = el.parentNode;
	}
    }
});

Уменьшайте отрисовки (reflows)

  • Отрисовка экрана происходит каждый раз при манипуляциях с DOM-деревом.
  • У браузеров есть ряд оптимизаций, чтобы уменьшить число отрисовок, в частности:
    • Изменение невидимого элемента (display:none) не вызывают отрисовку
    • Изменение элемента, не входящего в DOM ("off-DOM") не вызывает отрисовку
  • Групповое изменение стилей:
    • Изменяйте значение атрибута style при помощи метода setAttribute (не работает в Internet Explorer). Пример:
      el.setAttribute("style", "display:block;width:auto;height:100px;...");
    • Изменяйте значение свойства cssText объекта style. Пример:
      el.style.cssText = "display:block;width:auto;height:100px;...";
    • Более масштабируемо: изменяйте название CSS класса у элемента. Пример:
      YAHOO.util.Dom.replaceClass(el, "foo", "bar");

Разные советы...

  • Может быть, стоит использовать событие onmousedown вместо onclick
    • Используйте как преимущество удаление небольшой задержки между нажатием кнопки мыши и ее освобождением пользователем.
  • «Переключите ваш код на первую передачу»: устраните частые и ресурсоемкие действия

Часть 5. Высокопроизводительный динамический макет и CSS

Разные советы...

  • Используйте технику CSS Sprites для быстрого переключения картинок (Snappy Image Replacement, известен также как rollover-эффект).
  • Избегайте использования JavaScript для (анимации) макета.
    • Нужно помнить о window.onresize...
    • Вместо этого используйте чистый CSS!
    • Побочные эффекты: улучшается масштабируемость, улучшается поддержка пользователей с отключенными возможностями (скриптами, изображениями, стилями), и т.д.
  • Избегайте использования CSS-выражений (expressions) в Internet Explorer.
    • Выражения (в большинстве своем) постоянно пересчитываются, чтобы учесть текущие изменения на странице.
    • Существуют способы по их оптимизации, но, в общем случае, можно найти обходные пути, чтобы их не использовать.
  • Избегайте использования CSS-фильтров в Internet Explorer (или сведите их к минимуму).
  • Оптимизируйте табличную разметку.
    • Задача: позволить движку браузера начать отображение таблицы перед тем, как он ее полностью получит.
    • Используйте table-layout:fixed
    • Дополнительно определите элемент COL для каждой колонки.
    • Задайте значение для его атрибута WIDTH.
  • Оптимизируйте ваши CSS-селекторы [http://developer.mozilla.org/en/docs/Writing_Efficient_CSS]. Стоит заметить, что большая часть этих советов, в связи с проведенным исследованием, не несет особого смысла.

Часть 6. Высокопроизводительный Ajax

Практический Ajax

  • Никогда не применяйте синхронный XMLHttpRequest.
    • http://yuiblog.com/blog/2006/04/04/synchronous-v-asynchronous/.
    • Асинхронное программирование лишь незначительно сложнее.
    • Никогда не блокируйте весь или даже часть интерфейса пользователя при ожидании транзакции.
  • Программно обрабатывайте сетевые тайм-ауты.
  • Решение: используйте YUI Connection Manager:
    var callback = {
        success: function () { /* Что-нибудь делаем */ },
        failure: function () { /* Что-нибудь делаем */ },
        timeout: 5000
    };
    
    YAHOO.util.Connect.asyncRequest("GET", url, callback);

Улучшайте видимые сетевые задержки используя оптимистичный шаблон

  • Если данные проверяются локально (на клиенте при помощи JavaScript) перед их отправкой на сервер, то запрос будет успешным в 99,9% случаев, (также фактическая реакция «сервера» на действия пользователя будет более быстрой).
  • Следовательно, для оптимизации пользовательского восприятия стоит предполагать успешный результат и прибегать к следующему шаблону:
    • Обновить UI при отправке запроса.
    • Заблокировать UI/структуру данных, по возможности, наиболее точечно.
    • Дай пользователю понять, что что-то произошло.
    • Дать пользователю понять, что объект UI заблокирован.
    • Разблокировать UI/структуру данных, если результат был успешным.
    • Максимально мягко обрабатывать возможные ошибки.

Разные советы...

  • Помните о максимальном количестве одновременных HTTP/1.1 соединений.
  • По возможности множьте ваши Ajax-запросы, если ваш сервер это сможет поддерживать.
  • Добавляйте дополнительные сообщения в ответ для Ajax-запроса.
  • Выберите JSON вместо XML в качестве формата обмена данных
    • Доступ к JSON-данным осуществляется проще и требует меньше ресурсов, чем для XML.
    • У JSON меньше накладных издержек.
  • Добавляйте, не спрашивая. Используйте технологию COMET для отправки уведомлений браузеру в режиме реального времени.
  • Рассмотрите возможность использовать локальные данные (local storage) или локальный кеш, запрашивая с сервера только изменения:
    • userData для Internet Explorer
    • Локальные данные для Flash
    • DOM:Storage (стабильное API для хранения данных от WhatWG, реализовано в Firefox 2)
    • Google Gears
    • и т.д.

Часть 7. Инструменты для производительности

Читать дальше

Все комментарии (habrahabr.ru)