JSONP для инициализации страницы

Блоки с динамическим содержимым уже давно принято обновляться асинхронными запросами на сервер. А вот для наполнения их начальными данными эта техника не слишком хорошо подходит из-за видимой задержки в появлении внешнего оформления блока и самого содержимого блока. Чтобы минимизировать эту задержку данные уже должны находиться на странице во время ее загрузки. Очевидно, что при этом HTML захламляется вкраплениями JavaScript, что не слишком хорошо. Компромиссным вариантом может быть загрузка данных с помощью тега script.

Предположим, что на сервере есть контроллер, который отдает модель данных в виде JSON. Пусть URL, по которому можно получить эти данные, будет http://example.com/data/?page=1, а сами данные


{sites: [
    {id: 1, name: "Yandex.ru", url: "http://yandex.ru/"},
    {id: 2, name: "Google", url: "http://google.com/"},
    {id: 3, name: "NotesKeeper", url: "http://noteskeeper.ru/"}
]}

Этот URL используется в асинхронном запросе, чтобы получить новую страницу блока. Если его подставить в тег script , то он, конечно же, будет загружен и исполнен, но возникнет синтаксическая ошибка, так как объект не был использован в операции присвоения или при вызове функции.

Добавим в параметры к URL еще один http://example.com/data/?page=1&callback=App.render и модифицируем контроллер на сервере так, чтобы этот параметр (при его наличии) подставлялся в выходные данные


App.render( {sites: [
    {id: 1, name: "Yandex.ru", url: "http://yandex.ru/"},
    {id: 2, name: "Google", url: "http://google.com/"},
    {id: 3, name: "NotesKeeper", url: "http://noteskeeper.ru/"}
]} );

Теперь такой адрес можно использовать в теге script. Когда данные будут загружены, то автоматически произойдет вызов указанной функции с моделью.

Контроллер интерфейса может иметь, например, такую структуру


var App = (function () {
    // скрытые переменные приложения
    return {
        // публичные методы приложения
        render: function (model) {
            // действия, которые можно выполнить до полной загрузки документа
            $(function () {
                // изменения в документе, который выполняются только
                // после его полной загрузки
                App.update(model);
            });
        },
        update: function (model) {
            // обновляем содержимое блока
        }
    };
}());

Когда мы получим от сервера модель с начальными данными, то дождемся сигнала о полной загрузке документа, чтобы безопасно можно было начать его изменения, и приступим к построению содержимого блока.

Эта техника и называется JSONP (JSON with padding). Основное применение она нашла в загрузке данных сторонних сервисов, например, таких как Flickr, Yahoo, Google и многих других. Из-за того, что асинхронные запросы для других доменов блокируются политикой безопасности браузера, использование этой техники наряду с iframe является, пожалуй, единственным возможным вариантом.

В одном из проектов, над которым я работаю в последнее время, такой прием успешно используется для загрузки граничных условий валидатора форм.