Skip to content
This repository was archived by the owner on May 6, 2025. It is now read-only.

Concept

Gems edited this page Aug 2, 2013 · 7 revisions

Main Idea

Подавляющее большинство сайтов имеет схожий внешний вид у своих внутренних страниц. Соответственно, во время навигации по сайту для пользователя чаще всего меняются только какие-то части страницы. Например, заменяется центральный текст на странице, подставляется другое название страницы и подсвечивается другой пункт меню. Возможно еще подгружается другой баннер.

Однако, каждый раз с сервера приходит весь HTML (+Images/CSS/Javascript), необходимый для показа этой страницы целиком, как если бы мы на нее просто зашли по прямой ссылке с какого-то другого ресурса.

Самый простой путь уменьшения объема — client-side шаблонизация, когда от сервера приходит только JSON-данные, а весь HTML создается яваскриптом в браузере. Но в таком случае сайт не может корректно показываться тем системам, которые не поддерживают javascript, и в частности поисковым системам.

Table of contents

Loading only necessary part of page

Если мы уже на сайте, и HTML, который размечает общий вид страницы уже у нас есть, то и не зачем этот общий вид еще раз подгружать — давайте спросим у сервера только ту часть, которую собираемся заменить.

А сервер, соответственно, должен уметь отдавать только часть страницы.

Например, мы находимся на главной странице сайта:

<!doctype html>
<html>
  <head>
    <title>Main page</title>
  </head>
  <body>
    <header id="FullUserData">
      UserName, UserMoney, NewMessagesForUser, SomeMoreInfoForUser
    </header>
    <aside id="SidebarNews">
      <h2>Some news</h2>
      <ul>
        <li>...</li>
        <li>...</li>
      </ul>
    </aside>
    <div id="MainContent">
      <h1>Main Page</h1>
      <p>You're on the Main Page of our Site!</p>
      <p>And you can navigate to <a href="/another_page/">another page</a>.</p>
    </div>
    <footer>Copyrights</footer>
</html>

Когда мы переходим по ссылке, то с сервера приходит следующий ответ

<!doctype html>
<html>
  <head>
  → <title>Another page</title>
  </head>
  <body>
    <header id="FullUserData">
      UserName, UserMoney, NewMessagesForUser, SomeMoreInfoForUser
    </header>
    <aside id="SidebarNews">
      <h2>Some news</h2>
      <ul>
        <li>...</li>
        <li>...</li>
      </ul>
    </aside>
    <div id="MainContent">
    → <h1>Another Page</h1>
    → <p>You're on the Another Page of our Site!</p>
    → <p>And you can navigate back to <a href="/">main page</a>.</p>
    </div>
    <footer>Copyrights</footer>
</html>

Можете обратить внимание, что изменившийся кусок HTML — только то, что содержится внутри <div> и служебная часть внутри <head>/<title>.

В нашем случае, мы можем к запросу на сервер добавить специальные request-header. Например:

X-Che-Sections: pageView: #MainContent
X-Requested-With: XMLHttpRequest

Сервер по этому заголовку достает pageView — в нашем случае, это центральное содержимое страницы, и возвращает нам response-header

  X-Che-Url: /another_page/
  X-Che-Url: /another_page/

и html:

<title>Another Page</title>
<section data-selector="#MainContent">
  <h1>Another Page</h1>
  <p>You're on the Another Page of our Site!</p>
  <p>And you can navigate back to <a href="/">main page</a>.</p>
</section>

Дальше мы находим на странице элемент с соответствующим селектором и заменяем его на содержимое из <section>.При этом через History.pushState подменяем url на тот, который пришел от севера.

В случае страниц с большим количеством HTML, то есть для большинства крупных сайтов, экономия пересылаемого кода весьма заметна. Плюс к тому, сервер не выполняет работу по сбору данных для тех кусков HTML, которые не поменялись (скажем, FullUserData, или SideBarNews, etc. ).

Caching page parts

Для еще большего ускорения работы система дополнительно кэширует приходящие куски HTML и хранит их LocalStorage. Ключом записи является связка url и данных о перезагружаемых секциях (аттрибут data-reload-sections у ссылок, либо форм)

Это связано с ситуацией, когда на страницу можно попасть с разных страниц. В этой ситуации возможно, что будут заменяться разные части страницы. Например, мы можем быть на странице новости и нажать ссылку «следующая новость». Тогда почти все останется на месте, изменится только текст новости и заголовки. А можем на эту же страницу придти с главной страницы, и тогда, наверянка, должна поменяться почти вся страница — другое имя блока, другой селектор.

Fallback

Важный момент в работе сервера, что он может работать как в двух режимах:

  1. Оптимизированный режим — выдача только части HTML, в ответ на соответствующий запрос с клиента.
  2. Стандартном режиме — то есть собирать целиком страницу по запросу. Это важно как для тех, кто заходит по прямым ссылкам, или набирает вручную нужный URL в адресной строке браузера, так и для поисковиков, которые вообще ничего не знают про JavaScript и индексируют только HTML.

Widget concept

Загружаемую таким образом часть HTML удобно рассматривать, как своего рода виджет. В таком случае, мы можем в контексте этого блока загружать соответствующие только этому блоку скрипты и CSS.

Чтобы определить какие скрипты должны быть связаны с элементом, нужно в аттрибуте data-js-modules указать их через запятую. В результате, когда загружается страница, либо когда приходят новые секции скрипт определяет какие виджеты необходимы, загружает их и запускает инициализаю в контексте элемента.

При переходах, виджеты, элементы которых должжны быть изъяты, отключаются, их экземпляры продолжают существовать и при необходимости могут быть с легко включены. (например когда пользователь решил пойти назад по истории и ранее удаленные элементы вновь вставляются в DOM)

Using AMD

Improve speed of first loading by cookie

Clone this wiki locally