Подтвердить что ты не робот

Управление событиями document.ready на крупномасштабном веб-сайте

ПРИМЕЧАНИЕ. Теперь я создал плагин jQuery, который является моей попыткой решения этой проблемы. Я уверен, что его можно было бы улучшить, и я, вероятно, не обратил внимания на множество вариантов использования, поэтому, если кто-то хочет дать отзыв, не стесняйтесь:-) https://github.com/WickyNilliams/ReadyBinder

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

В основном, я работаю на крупномасштабном веб-сайте, и все чаще мы пишем все больше и больше JavaScript. Это прекрасно, я наслаждаюсь уникальным подходом JS, и я нахожу причудливость в некоторых более темных летописях языка, чтобы быть привлекательными;-) Однако одна вещь, которая всегда меня беспокоила, - это то, как управлять документами, готовыми к событиям, поскольку они становятся все более крупными со временем (и, как результат, менее сфокусированным/специфичным для обслуживаемой страницы)

Проблема заключается в том, что у нас есть один JS файл (объединенный и сокращенный, хотя такой несущественный для моих вопросов). Большая часть JS написана с использованием шаблона раскрывающего модуля, а jQuery - наша выборка. Таким образом, вся наша JS funcitonality логически сгруппирована в методы, namespaced, а затем прямо внизу файла script у нас есть это

$(function(){
    //lots of code here, usually calling encapsulated methods 
    //on our namespaced revealing module
});

Проблема заключается в том, что не весь код в этом документе готовый обработчик относится к каждой странице. Например, на одной странице только 10% из них могут быть релевантными, а может быть, еще и 80%. Для меня это кажется невероятно неправильным, я чувствую, что должен выполнять только код, который мне нужен на странице, в основном для эффективности, но также и для удобства обслуживания.

Я искал google для подходов к этой проблеме, но ничего не могу найти, может быть, я просто искал неправильную вещь!

В любом случае, мои вопросы:

  • Кто-нибудь когда-нибудь думал об этой проблеме?
  • Это действительно проблема в глазах других людей?
  • У вас есть большой, всеохватывающий документ, готовый обработчик в вашем коде, или он более сфокусирован на типе страницы, обслуживаемой?
  • Если последнее, как вам это удается? Несколько обработчиков, которые переключаются в JS или динамически выплескивают сервер документа на стороне документа?

Посмотрите на мысли людей по этому поводу.

Приветствия

4b9b3361

Ответ 1

Это то, что я сделал в моем проекте mvc rails с тяжелым javascript, я создал отдельное пространство имен для контроллеров в js, которое напоминает контроллер rails

class BusinessController
   def new
   end  
   def index
   end
end

и

Var Business =  {
      init : function(action) {
         //code common to the Business module
         //even add the common jquery doc ready here, its clean
         //and call the page specific action
         this[action]();
      },
      new : function() {
             // check jquery document ready code here, thats relevant to this action
             //New rental page specific code here
      },
      index : function() {
             //  check jquery document ready code here, thats relevant to this action
             //index rental page specific code here 
      }
}

а в коде просмотра (на стороне сервера) просто запустите код js для страницы с помощью

<script type="text/javascript"> 
 <%= controller_name %>.init('<%= controller.action_name %>'); 
//which will render to
//  Business.init(index);
</script>

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

Ответ 2

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

Если ваш код выглядит примерно так:

$(function () {
    // Binds a single click event (which will never be triggered if the hypothetical
    // widget is never used), regardless of how many widgets are used on the page.
    $(document).delegate('.rating-widget', 'click', namespace.rating.handler);
    // and so on for similar things which simply require event handler registration

    // Initializes each of the forms on the page, letting the initializer take care
    // of any details (datepicker widgets, validation, etc) based on the root element
    $('form.fancy').each(namespace.fancyform.initializer);
    // and so on for similar things that require initialization

    // ... (for each type of thing on the page requiring initial setup,
    //      find the most general/high level pattern that sufficient)
});

вещи должны быть относительно поддерживаемыми, даже если есть несколько десятков строк. На этом уровне нет сложной/интересной логики для обновления/запоминания при работе с кодом компонента, и, поскольку все на этом уровне тривиально, его легко читать. На данный момент нет необходимости изобретать сложную систему регистрации; это не будет проще, чем .delegate и .each.

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

Для интересных идей о том, как вы можете реализовать обработчики/инициализаторы, вы можете взглянуть, например, на " Контекстный jQuery на практике", который Doug Neiner дал в jQuery Boston на прошлой неделе.

Ответ 3

Отличный вопрос. Я действительно справляюсь с этим, используя пользовательские события загрузки страницы. Так что в моем основном файле .js у меня есть класс вроде следующего:

var Page = {
    init: function(pageName) {
        switch (pageName)
        {
            case: 'home': {
                // Run home page specific code
            }
            case: 'about': {
                // Run about page specific code
            }
            ...
        }
    }
}

Вы можете называть это путями, либо в конкретном для страницы $(document).ready(), либо в ядре script с использованием какого-либо анализатора URL (буквально все возможно с парсером URL):

$(document).ready(function() {
    // http://www.mydomain.com/about
    var currentPage = window.location.pathname;   // "about"
    Page.init(currentPage);    
});

window.location Ссылка DOM: https://developer.mozilla.org/en/DOM/window.location

Ответ 4

Сначала я помещаю определенные классы в тело или в определенные контейнеры, например. articles, form-validation, password-meter,.... Если у меня есть приложение MVC, я предпочитаю помещать имя контроллера в класс тела. Это не повредит много и может быть полезно для стиля тоже.

Затем на каждом блоке document.ready я проверяю существование такого класса, и если он не существует, я возвращаюсь из этой функции. Этот подход проще, поскольку он не имеет основного кода внутри предложения if. Этот подход похож на утверждения, которые используются для проверки предпосылок функции.

Пример:

$(function(){
    if($('body').hasClass('articles') === false){ return; }

    //body of the articles code
});

$(function(){
    if($('body').hasClass('password-meter') === false){ return; }

    //include password meter in page
});

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

Ответ 5

Я знаю, откуда вы. Правильные webapps для использования в мобильных устройствах могут показаться глупыми, чтобы пользователь загрузил массивный JS файл, полный нерелевантного кода (JQuery API для одного - это плохой старт!).

То, что я делаю, что может быть правильным или неправильным, но, безусловно, кажется, работает, включает в себя необходимые функции на странице за страницей перед тегом. (Эта позиция по большей части обходится вокруг документа. Уже выпущена). Все же не может не чувствовать, что этот подход слишком прост.

Мне интересно услышать другие ответы, хотя это хороший вопрос, +1.

Ответ 6

"Проблема в том, что у нас есть один JS файл"

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

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

Я не могу сказать из вашего вопроса, знаете ли вы об этом, но у вас может быть несколько обработчиков документов (я считаю, что jQuery выполняет их в том порядке, в котором они были связаны?). Поэтому, если вы разделите JS, каждый JS файл может включать в себя собственный документ. Конечно, этот подход имеет свои собственные накладные расходы, но я думаю, что это лучше, чем положить все в один файл.

Ответ 7

Во-первых, если вы используете jQuery, document.getElementsByTagName действительно не нужно, вы можете просто использовать $( "тэг" ). Посмотрите документацию jQuery Selectors для еще большего волшебства!

Ваше незавершенное решение - это то, как я это делал, но вам не нужно беспокоиться о том, чтобы определить дополнительные функции, получить bodyClasses, запустить цикл или любой из этих джазов... почему бы просто не использовать функцию jQuery . hasClass()?

$(function() {
    if($("body").hasClass("article")) {
        alert("some article specific code");
    }
    if($("body").hasClass("landingPage")) {
        alert("some landing specific code");
    }
});

Bam. Все, что тебе нужно. Если вы хотите быть более эффективным, вы можете повторно использовать один запрос тела:

$(function() {
    var body = $("body");
    if(body.hasClass("article")) {
        alert("some article specific code");
    }
    if(body.hasClass("landingPage")) {
        alert("some landing specific code");
    }
});

Здесь он находится на jsfiddle: http://jsfiddle.net/W8nx8/6/

Ответ 8

Наличие меньше файлов javascript минимизирует количество запросов, отправленных на сервер, и кеширование файлов ускоряет загрузку второй и третьей страниц. Обычно я думаю о вероятности того, что некоторые части js файла понадобятся на следующих страницах (а не только на текущей странице). Это заставляет меня классифицировать код js на два типа: код, который входит в мой "main.js", и даже если он не используется, он будет загружен клиентом (но не обязательно будет выполнен, я объясню), а вторая категория кода идет в отдельных файлах. Вы могли бы создать несколько файлов, сгруппированных по вероятности. Это зависит от деталей вашего проекта. Если это крупномасштабный проект, запуск статистического анализа поведения пользователя может выявить интересные способы группировки js-кода. Теперь, когда код был загружен клиенту, мы не хотим его исполнять. То, что вы должны сделать, это разные макеты или страницы. Поместите частичное изображение в макет или страницу. Внутри частичного набора используется переменная javascript. Измените javascript-переменную в коде javascript и определите, хотите ли вы выполнить какой-либо код или нет.

то есть:

Создайте частичный "_stats.html.erb", поместите в него этот код:

<script type="text/javascript">
    var collect_statistics = <%= collect_statistics %>;
</script>

Поместите частично на страницы, которые вы хотели бы собирать: show.html.erb

<%= render "_stats", :collect_statistics => false %>

Теперь в вашем js файле выполните следующие действия:

$(document).load( function() {
 if (typeof collect_statistics != "undefined" && collect_statistics) {
  // place code here
 }
});

Надеюсь, это поможет!

Ответ 9

Мне нравится подход RameshVel. Я также нашел камень Paloma, чтобы создать JavaScript для конкретных страниц. Например:

Paloma.controller('Admin/Users', {
  new: function(){
    // Handle new admin user
  }
});