Лучшие практики управления JavaScript в одностраничном приложении - PullRequest
5 голосов
/ 06 мая 2010

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

У меня уже есть модуль History, отслеживающий хэш местоположения, который может выглядеть как domain.com/#/company/about, и класс Page, который будет использовать XHR для получения содержимого и вставки его в область содержимого.

function onHashChange(hash) {
    var skipCache = false;
    if(hash in noCacheList) {
        skipCache = true;
    } 
    new Page(hash, skipCache).insert();
}


// Page.js
var _pageCache = {};
function Page(url, skipCache) {

    if(!skipCache && (url in _pageCache)) {
        return _pageCache[url];
    }
    this.url = url;
    this.load();

}

Кэш должен позволять страницам, которые уже были загружены, пропускать XHR. Я также сохраняю содержимое в documentFragment, а затем вытаскиваю текущее содержимое из документа, когда вставляю новый Page, поэтому браузер должен будет создать DOM для фрагмента только один раз.

Пропуск кэша может потребоваться, если на странице есть данные, чувствительные ко времени.

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

Каков наилучший способ загрузки этого JavaScript на страницу? Включить теги сценария в фрагмент документа, который я получил от XHR? Что делать, если мне нужно пропустить кэш и повторно загрузить фрагмент. Я чувствую, что тот же самый JavaScript-код, вызываемый во второй раз, может вызвать конфликты, например, повторное выделение тех же переменных.

Будет ли лучший способ прикрепить сценарии к голове при получении нового Page? Это потребовало бы, чтобы исходная страница знала все ресурсы, которые могут понадобиться каждой другой странице.

И кроме того, что я знаю, как лучше всего включить все, не нужно ли мне беспокоиться об управлении памятью и возможных утечках при загрузке стольких различных бит JavaScript в один экземпляр страницы?

Ответы [ 7 ]

1 голос
/ 07 июня 2010

О, мальчик, тебе повезло. Я только что провел все эти исследования для своего собственного проекта.

1: Хеш-событие / менеджер, который вы должны использовать, это барбекю Бена Алмана: http://benalman.com/projects/jquery-bbq-plugin/

2: чтобы поисковые системы любили вас, вам нужно следовать этому очень ясному набору правил: http://code.google.com/web/ajaxcrawling/docs/specification.html

Я нашел это поздно и игру, и мне пришлось отбросить большую часть моего кода. Звучит так, будто вам тоже придётся отказаться, но в результате вы получите гораздо больше.

Удачи!

1 голос
/ 20 мая 2010

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

Тогда, когда это произойдет, вам не нужно перезагружать теги сценария для этих страниц, если они еще не загружены на страницу?

Если это так, вы можете попробовать захватить все теги со страницы, прежде чем вставлять новый HTML в DOM:

//first set up a cache of urls you already have loaded.
var loadedScripts = [];

//after user has triggered the ajax call, and you've received the text-response
function clearLoadedScripts(response){
   var womb = document.createElement('div');
   womb.innerHTML = response;
   var scripts = womb.getElementsByTagName('script');
   var script, i = scripts.length;
   while (i--) {
      script = scripts[i];
      if (loadedScripts.indexOf(script.src) !== -1) {
          script.parentNode.removeChild(script);
      }
      else {
          loadedScripts.push(script.src);
      }
   }

   //then do whatever you want with the contents.. something like:
   document.body.innerHTML = womb.getElementsByTagName('body')[0].innerHTML);

}
0 голосов
/ 08 июня 2010

Лично я бы передавал JSON вместо необработанного HTML:

{
    "title": "About",
    "requires": ["navigation", "maps"],
    "content": "<div id=…"
}

Это позволяет отправлять метаданные, такие как массив необходимых сценариев, вместе с содержимым. Затем вы должны использовать загрузчик скриптов, например, один из упомянутых выше, или свой собственный, чтобы проверить, какие из них уже загружены, и сбросить те, которые не загружены (вставив их в <head>), перед рендерингом страницы. .

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

0 голосов
/ 05 июня 2010

Вы можете использовать загрузчик скриптов, такой как YUI Loader, LAB.js или другой, например jaf

Jaf предоставляет вам механизм для загрузки представлений (фрагментов HTML) и соответствующих им файлов js, css для создания одностраничных приложений. Проверьте пример приложения списка задач. Хотя он еще не завершен, все еще есть много полезных библиотек, которые вы можете использовать.

0 голосов
/ 22 мая 2010

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

Несколько вариантов, которые я могу придумать:

  1. Позволяет серверу контролировать, какие теги сценария включены . передайте список уже загруженных тегов сценария с помощью запроса XHR и попросите сервер разобраться, какие дополнительные сценарии необходимо загрузить.
  2. Загрузите все сценарии заранее (возможно, добавьте их в DOM после страницы, загруженной для экономии времени), а затем забудьте об этом. Для сценариев, которые должны инициализировать пользовательский интерфейс, просто включите каждый запрашиваемый вызов страницы в тег сценария, который вызывает глобальную функцию инициализации с именем страницы.
  3. Пусть каждая запрашиваемая страница вызывает JS-функцию , которая работает со скриптами загрузки / кэширования . Эта функция будет доступна из глобальной области видимости и будет выглядеть следующим образом: require_scripts('page_1_init', 'form_code', 'login_code') Затем просто сохраните список загруженных сценариев и добавьте теги DOM-сценариев только для сценариев, которые еще не загружены.
0 голосов
/ 07 мая 2010

У вас есть контроль над загрузкой этих страниц?Если нет, я бы порекомендовал вставить загруженную страницу в IFrame.

Извлечение скриптов страницы из контекста и вставка их в заголовок или добавление их в другой элемент HTML может вызвать проблемы, если вы точно не знаете, какpage is build.

Если у вас есть полный контроль над загружаемыми страницами, я бы порекомендовал вам конвертировать весь ваш HTML в JS.Это может показаться странным, но на самом деле конвертер HTML-> JS не так уж и далеко.Вы можете начать с Pure JavaScript HTML Parser , а затем позволить анализатору выводить JS-код, который, например, создает DOM с использованием JQuery.

Я собирался пойти по этому пути длянекоторое время назад в веб-приложении, над которым я начал работать, но теперь я передал его подрядчику, который преобразовал все мои чистые страницы JS в HTML + JQuery, что бы ни делало его ежедневную работу продуктивной, мне все равно, но я действительно был в этой чистойJS webapp подход и обязательно попробую.

0 голосов
/ 07 мая 2010

Я никогда не создавал такой сайт, поэтому я не знаю, является ли это наилучшей практикой, но я бы добавил некоторую управляющую информацию (например, комментарий или заголовок HTTP) в ответ и позволил скрипту загрузчика обрабатывать проверка избыточности / зависимости и добавление тегов сценария в заголовок.

...