Pull to refresh

Comments 59

«2 потока загрузки модулей: для dom-base-utils и для dom. „
судя по коду “utils-base-dom»? или я ошибся?

в примере есть yass-component-counter, но counter.js не грузится, я наверное не понял примера, для чего используется «yass-component-counter»?

*а вообще — шикарно! это же практически язык js-макросов на базе css…
awesome!
сорри, комментарий чуть ниже
да, спасибо, поправил. Там порядок «наследования» функционала: сначала самый простой, потом более сложные. Т.е. utils ничего не требует для загрузки, base требует utils, а dom требует base.

А как проявляется то, что counter.js не грузится? Под каким браузером?
ff3.1
firebug показывает что не грузится
что он должен изменять?

*dom-base-utils еще остался чуть ниже
если на странице есть 'Counter loaded' — Значит, загрузился :)
проверь, плиз, сейчас. Классический race condition, однако, возник :)
спасибо большое. Вполне возможно, что сбоит алгоритм выбора модулей по CSS-селектору. Буду искать тестовое окружение :)
я поставил 3.1 beta2 — у меня проблемы не наблюдалось :(
виновник безобразия найден — это AdBlock Plus
ключевое слово «counter» ему сильно не нравится :)
без него все в норме
ух, прикольно :) сейчас переименую модуль :)
пытаюсь прикрутить один тест
не работает такое наименование «yass-component-/scripts/fontface.js»
стоит сделать

* кручу дальше, будет пример :)
я а может багу нашел, тестовая страница отвечает обычно так
ClientSide is loaded
Counter is loaded
но иногда и так
ClientSide is loaded
ClientSide is loaded
ClientSide is loaded
ClientSide is loaded
Counter is loaded
это нормально?
нет, ненормально. Хорошо бы браузер, в котором вылазит. Асинхронность — такая весчь…
угу, удалось поймать лог для IE. Буду смотреть, где стыковки разрушились :) Спасибо сетевым задержкам
итак, обещанный пример:

во-первых я немного изменил yass (сорри):
«script.src=alias+».js";script.type=«text/javascript»;"

во-вторых, я добавил в body такой класс:
«yass-component-/scripts/fontface»

в-третьих, я создал такой fontface.js:
if (navigator.userAgent.indexOf('Windows NT 6.0') == -1) {
$('body').css(«font-family», '«Calibri2»');
}

в четвертых, в css есть такое определение:
@font-face {
font-family: «Calibri2»;
src: url("/content/calibri.ttf") format('truetype');
}

что имеем в итоге? в итоге, опльзовтаели Vista не грузят больше calibri.ttf размером в 300 килобайт (этот шрифт уже установлен в виста), другие юзеры шрифт грузят. Осталось добавить фильтрацию по браузерам, которые не поддерживают font-face и мы сократим траффик на порядок :)

Ура, YASS!

смотреть на nuke.wyob.ru/css3test/
1. _.ua = navigator.userAgent
2. $('body').css(«font-family», '«Calibri2»') === _('body')[0].style.fontFamily = 'Calibri2'

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

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

предлагаю примерно следующий вариант решения
var Optimizer = function(ops){
  var scope = ops.scope ? ops.scope : window;
  scope[ops.name] = function(arg){
    if (scope[ops.name].once) return;
    scope[ops.name].once = true;
    var text = null;
    dax({url:ops.script, id:ops.script, destroy:true, async:false, callback: function(resp){
      text = resp.responseText;
    }})
    SRAX.evalScript(text);
  }
}
new Optimizer({scope:Ext, name:'NorthLayoutRegion', script:'/scripts/ext/separate/layoutregion.js'})
new Optimizer({scope:Ext, name:'ContentPanel', script:'/scripts/ext/separate/contentpanel.js'})
new Optimizer({scope:Ext.dd, name:'StatusProxy', script:'/scripts/ext/separate/statusproxy.js'})
new Optimizer({scope:Ext.dd, name:'DragSource', script:'/scripts/ext/separate/ddzone.js'})
new Optimizer({scope:Ext.dd, name:'DropTarget', script:'/scripts/ext/separate/ddzone.js'})


* This source code was highlighted with Source Code Highlighter.

это примеры из реального проекта, правда относительно давно писалось, во времена extjs v1.

Суть в следующем:
Optimizer — это так называемый proxy — создает заглушки классов, методов. Он знает в каком файле лежит нужный метод. При первом вызове метода вызывается его заглушка, которая догружает фал с асинхронном/синхронном режиме, выполняет загруженый скрипт (тут происходит перезапись заглушки на реальный метод, класс), выполняет повторно вызванный метод.
При повторных вызовах методов, классов — вызываются уже не заглушки, а реальные методы, классы.

P.S.: Код Optimizer примерный, чтобы понять принцип.
да, только нам придется знать все заглушки тогда :)
но подход интересный
суть в том чтобы сделать Optimizer нормальный, а заглушки разработчик сам определит.
кажется история делает виток, скоро будут полноценные аналоги динамических dll-библиотек
скоро будут полноценные ОСи в браузерах, не то что какие dll :)
ну и получится как на яндексе — сначала загружается страница, где ничего не работает, а потом несколько секунд грузятся десятки скриптов и стилей…
:) кому что нравится. Лично мне очень не хватало динамической загрузки счетчика от Гугла. А дерево приведено только для примера, никто не мешает загружать все в 2-3 файлах.
при 2-3 файлах совершенно не нужно городить яваскриптовый огород вокруг зависимостей, динамических подгрузок, волшебных стыковок компонентов друг с другом и прочей фигни.
совершенно верно. Но почему не подключить дополнительные полкилобайта кода, чтобы весь этот огород получить? Сейчас yass в пожатом виде занимает 3 Кб
только ты не учитываешь, что хтмл разрастается неимоверно, а надёжность всей этой конструкции падает ввиду увеличения её сложности.

вот, допустим, у тебя есть компонента «подтверждение при клике». пока она одна — подумаешь, прописать пару лишних классов с гигантскими именами, да запихнуть в тайтл (чтобы при наведении код показывал? о_0) текст с вопросом.
но что если нужно вывести табличку с кучей кнопочек «удаления с подтверждением»? получится гора копипасты.
вообще говоря, пихать яваскрипт код в аттрибуты элементов — ничем не лучше, чем пихать пхп код в хтмл. ибо логика имеет свойство разрастаться и превращаться в длиннющую простыню…

зачем нам прописывать все в HTML? достаточно родителей модулей указать
Отвечая на предыдущий комментарий: у нас есть, фактически, три способа выполнить что-то «по загрузке» скрипта:
1. Указать функцию в самом низу файлу модуля
2. Указать обработчик для дерева модулей через _.modules[modules_alias].init
3. Указать обработчик через атрибут title в HTML-коде

Первые два способа никак не влияют на HTML-код. Третий — лишь для «быстрой» загрузки внешних модулей.

Далее, если у нас есть какой-то компонент clientside, то мы можем привязать всю логику к class=«yass-component-clientside» — этот элемент будет родительским для блока, отвечающего за функционирования данного компонента.

В самом примере классы в HTML вынесены только в демонстрационных целях. С таким же успехом можно указать дерево через _.load в конце скриптов (например, так сделано для yass.animation.js).
параметры модуля для конкретного узла всё-равно нужно будет тянуть простынёй…
что такое «параметры модуля для конкретного узла» и чем это будет отличаться от «обычного» JS-программирования? Можно пример?
ну вот, например, чуть выше я упомянул компоненту «переспросить». в зависимости от ссылки нужно задавать разные вопросы.
отлично. Все такие ссылки располагаются внутри контейнера, который загружает требуемый модуль. Модуль обходит все ссылки внутри контейнера и в зависимости от ссылки вешает какой-то обработчик.

Или я снова что-то не понял?
представь таблицу в правой колонке которой располагаются кнопки удаления. в других ячейках — другие ссылки. общий контейнер для всех ссылок удаления — таблица. при клике на кнопку удаления должно выскакивать сообщение «вы действительно хотите удалить запись ?»
а чем это отличается от описанного примера?

Проходит по таблице и навешиваем обработчики на ссылки удаления. По нажатию на ссылку у нас есть e.target, который позволяет получить все необходимые параметры. Чего нам еще не хватает?
для каждой ссылки удаления нужно формировать свой текст.
предлагаешь создавать по отдельной компоненте на «подтверждение удаления», «подтверждения бана», «подтверждения ещё чего-нибудь»?

емнип, обработчик клика нужно вешать на саму ссылку, иначе её уже будет не остановить…
но сейчас-то эти ссылка на «бан» и «удаление» как-то различаются? что мешает это различие и использовать?
предлагаешь внутри компоненты сделать гигантский свич с текстами для всех вариантов ссылок и кодом для вычленения названия удаляемого материала из окружающей эти кнопки разнообразной вёрстки? это уже будет далеко не 3кб…
а какое решение предлагаешь ты, что он не совместимо с описанным подходом?
ну, так не интересно :)

Просто моя позиция такова, что описанный подход не делает ничего лишнего. Он просто позволяет пользоваться тем, что уже было, более удобным образом. И все.
а моя — что в вёрстке не должно быть никаких скриптов — только данные. а скрипты уже сами должны разбираться с какими данными как работать. в частности, вместо того, чтобы давать элементам классы с именами модулей, лучше давать им классы с семантическими именами. а будет ли их «обогащать» один модуль, другой, или оба вместе — должны решать сами модули.

например, я недавно сделал такую фичу, что для любой текстарии можно указать аттрибут v:maxLength=«100» и к ней подключится два модуля — валидатор форм, не дающий засабмитить форму, если значение в текстарии превышает лимит, и корректор длинны, который автоматом удаляет лишние символы, не давая пользователю возможности превысить лимит. при этом они друг от друга не зависят и выход из строя одного никак не скажется на работоспособности другого. и если я их захочу объединить или наоборот разделить на ещё большее число частей — вёрстку переделывать не придётся, ибо там содержится вся необходимая и достаточная информация, без излишних имён модулей, их параметров и прочей вторичной инфы.
:) а если завтра придется сделать ограничение 120? Вводить параметры в HTML-элементы еще большее зло — тут уже никакой семантикой не прикроешься. А класс yass-module-textarea и(ли) restricted-length вполне себе семантичен.
ограничение длины определяет серверный экшен, который прописан в форме. форма, собственно, для того и предназначена, чтобы указывать что и в каком виде передавать на сервер. ес-сно ограничения, типы, имена и прочее по хорошему должны определяться моделью, а не хардкодиться в каждом шаблоне, но уж точно не стоит их задавать глобально для всего сайта в яваскрипте.

зачем писать yass-module-textarea, если уже и так написано два тэга textarea? лучше уж yass-rich.

и, кстати, yass пора переименовывать в yajf :-)
может тогда, jfyi или sdviusnvios? O_o

нашу дискуссию можно вести бесконечно :)
ну, yet another css selectors твоему фреймворку уже совсем не подходит…

кстати, как насчёт того, чтобы не захламлять глобальную область видимости своими переменными?

мисье страдает дискуссофобиями? тогда добро подаловать к нам, на процидурки B-)
в глобальной области видимости всего 2 переменные: yass и _
не всего… а целых две переменные! =)
если _ уже определена, то вообще одна!
Использовал похожий загрузчик в одном из разработанных проектов (1й метод из приведённых).
Страничка логина появлялась на экране сразу, что позволяло вводить username/password, пока грузятся компоненты (JS и CSS файлы).
Загрузка происходила за несколько секунд (подключались тяжеловесные компоненты: ExtJS, Google Maps, etc), этого времени как раз хватало, чтобы ввести пароль.

Результат подобного подхода налицо — мгновенная доступность сервиса для пользователя.
Время загрузки первой HTML странички минимально. Можно интегрировать стили в неё же (так делает Google, например).

Всё же, для большинства проектов подобный подход сродни «из пушки по воробьям».
Достаточно корректно прописать правила .htaccess (заголовок Expires), чтобы браузер закэшировал скрипты после первой загрузки.

Вывод: метод замечательный, но используем там, где необходимо (руководствуемся здравым смыслом).
А вот мой js-loader на mootools:
var jsLoader = new Class({
  Implements: Options,
  
  loadModel: {},
  options: {  
    version:   «0.1.1»,
    path:     "/source/js/",
    cache:     true
  },
  
  initialize: function(files, options){
    var self = this;
    window.addEvent(«load», function (event) {
    self.setOptions(options);
    if(!Browser.Engine.trident){
      console.time(«module load»);
    }
  
    if($defined(files)){
      files.each(function(file){
        self.load(file);
      });
    }
    
    if(!Browser.Engine.trident){
      console.timeEnd(«module load»);
    }
    window.fireEvent(«loadMoule»);
    });
  },
  
  load: function(file){
    var code = '';
    if(this.loadModel[file] && this.loadModel[file] >= this.options.version) return false;
    var js = new Asset.javascript(this.options.path+file+".js", { onload: function(){
      window.fireEvent(file);
    }});

    this.loadModel[file] = this.loadModel[file]? Math.max(this.loadModel[file], this.options.version): this.options.version;
  }  
});

* This source code was highlighted with Source Code Highlighter.
Давно занимался поиском таких скриптов. Просмотрел JsLoader, modules.js, lazyload, загрузчики под YUI, jQuery, Prototype.
Остановился на JSLoad (http://www.instructables.com/community/Free-Code-JSLoad/). Немного дописал и пользуюсь. Сначала определяешь зависимости, затем в нужном месте пишешь JSLoad.load('test', function() {alert('test loaded')}).
За JSX спасибо, попробую в бою.
Sign up to leave a comment.

Articles