Javascript-форум (https://javascript.ru/forum/)
-   Ваши сайты и скрипты (https://javascript.ru/forum/project/)
-   -   Мой синхронный костыль (https://javascript.ru/forum/project/24115-mojj-sinkhronnyjj-kostyl.html)

x-yuri 23.12.2011 14:06

Цитата:

Сообщение от FINoM
Примеры я уже приводил, вот хотя-бы этот:

Цитата:

Сообщение от FINoM
Рассмотрим пример (который взят из головы и в нем возможны ошибки) гипотетического парсера сайта

думаю, комментарии излишни

Цитата:

Сообщение от FINoM
Это дело твоё, хочешь, напиши функции setState, getState, я ведь тебе не указ, как и ты мне.

использование одной функции вместо двух для геттеров/сеттеров - довольно распространенная практика

Цитата:

Сообщение от FINoM
Да, ты прав, я люблю, когда всё просто. Самые популярные вещи — просты в использовании, посмотри на ту же "быдло-библиотеку" jQuery.

ты хочешь славы и популярности? Миллионы леммингов не могут ошибаться? И почему ты ее ставишь в пример, если сам называешь быдло-библиотекой? jquery - это хорошо, для каких-то задач. Но для чего-то более сложного начинает не хватать объектов, и не только.

Цитата:

Сообщение от FINoM
А если усложнить, то, вполне возможно, придется переделывать.

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

Цитата:

Сообщение от FINoM
А если усложнить, то, вполне возможно, придется переделывать. Ты сам пишешь: "Хорошие библиотеки возникают из решения практических задач". что бы это не значило, нужно отталкиваться от практических задач.

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

FINoM 23.12.2011 14:26

Цитата:

Сообщение от x-yuri
думаю, комментарии излишни

Думаю да. И зачем ты жирным выделил, хотел что-то доказать? Типа ситуации такой не бывает или что?
Цитата:

Сообщение от x-yuri
использование одной функции вместо двух для геттеров/сеттеров - довольно распространенная практика

Не важно. Повторюсь, создаешь объект this.object и он будет действителен во всей цепи. Если это решение не нравится, форкни скрипт на jsfiddle и сделай по-своему, я никого не ограничиваю в этом.
Цитата:

Сообщение от x-yuri
ты хочешь славы и популярности?

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

Сообщение от x-yuri
И почему ты ее ставишь в пример, если сам называешь быдло-библиотекой?

Пытаюсь найти с тобой общий язык. Ты любишь сложности, которыми jQuery похвастаться не может.
Цитата:

Сообщение от x-yuri
нет, это ты слишком упрощаешь.

Я не понимаю, какую задачу ты хочешь решить, вот и всё.
this.state('var', 5); // Программист: Состояние? Что за нахер? А если я хочу userState? Или varStack?
По крайней мере я бы задал эти вопросы и предпочел бы модифицировать this по-человечески, а не "тру".
Цитата:

Сообщение от x-yuri
"Напиши несколько парсеров сайтов, о которых ты говоришь, а потом подумай, как лучше решить эту проблему".

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

x-yuri 23.12.2011 14:26

...
Цитата:

Сообщение от FINoM
Это дело твоё, хочешь, напиши функции setState, getState, я ведь тебе не указ, как и ты мне.

конечно не указ, я просто объясняю свою точку зрения

x-yuri 23.12.2011 14:40

Цитата:

Сообщение от FINoM
Думаю да. И зачем ты жирным выделил, хотел что-то доказать? Типа ситуации такой не бывает или что?

я хотел показать, что ты придумал эту ситуацию

Цитата:

Сообщение от x-yuri
ты хочешь славы и популярности?

Цитата:

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

это была одна из возможных причин, почему ты привел jquery в пример

Цитата:

Сообщение от FINoM
Ты любишь сложности, которыми jQuery похвастаться не может.

ага, потому что она может похвастаться гораздо большими сложностями внутри. Ты когда-нибудь сталкивался с багами в jQuery? Пытался найти какая строчка их вызывает?

Цитата:

Сообщение от FINoM
this.state('var', 5); // Программист: Состояние? Что за нахер? А если я хочу userState? Или varStack?

ты всегда так придираешься к названиям API-методов? Соглашение про один метод используется даже в jquery

Цитата:

Сообщение от FINoM
По крайней мере я бы задал эти вопросы и предпочел бы модифицировать this по-человечески, а не "тру".

я ни разу не сказал, что мой путь - тру-путь. Я просто сравниваю свой вариант с твоим.

Цитата:

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

напиши еще два, говорят, хорошее решение приходит на третий раз ;) (шучу) Лучше выложи парсер, обсудим :)

FINoM 23.12.2011 15:01

Цитата:

Сообщение от x-yuri
я хотел показать, что ты придумал эту ситуацию

Ситуация с асинхронными вызовами не выдуманная и является самой известной проблемой при использовании ноды. "Псевдокод" который я привел, более чем понятен, на мой взгляд. Если всё-таки что-то не понятно, спрашивай, я объясню.
Цитата:

Сообщение от x-yuri
это была одна из возможных причин, почему ты привел jquery в пример

Хочу славы и популярности за 20 строк кода. Чего бы нет? А еще денег и баб.
Цитата:

Сообщение от x-yuri
Пытался найти какая строчка их вызывает?

Да. Просто скачивал неминимизированную версию и искал проблему.
Цитата:

Сообщение от x-yuri
Соглашение про один метод используется даже в jquery

Ты имеешь в виду .data()?
Цитата:

Сообщение от x-yuri
Лучше выложи парсер, обсудим

Это личное :)

x-yuri 23.12.2011 15:12

Цитата:

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

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

Цитата:

Сообщение от FINoM
Да. Просто скачивал неминимизированную версию и искал проблему.

ну если тебе все устраивает, тогда будем ждать пока тебе надоест :)

Цитата:

Сообщение от FINoM
Ты имеешь в виду .data()?

attr, html, prop, text, val, width, height

FINoM 23.12.2011 15:22

Цитата:

Сообщение от x-yuri
тогда будем ждать пока тебе надоест

Надоест, не надоест, более половины заказов по Javascript требуют использование jQuery. Так что выбор таков: потерять кучу денег из-за проблем, случающихся 1 раз на несколько тысяч строк кода, либо не выёбываться и работать.
Забыл главное: jQuery используется на > 50% сайтов во всём мире.
Чисто из любопытства: какие есть альтернативы? Мутулз — те же яйца, прототайп — вырвиглазное говнище...
Цитата:

Сообщение от x-yuri
attr, html, prop, text, val, width, height

Эти функции семантичны. Из их названия сразу понятно, что они делают. А тут ситуация такая: хранить переменные, которые могут быть чем угодно (шириной, показателем мягкости, сочинением "как я провел лето").

Gozar 23.12.2011 15:30

Ой, а я только сейчас заметил, что у меня получился вариант ну почти один в один как:
Цитата:

Сообщение от x-yuri (Сообщение 145312)
альтернативный вариант

Нужно попить колы для улучшения внимания.

А лично моё мнение что FINoM усложняет реализацию. Я взялся за написание решение после того как попытался разложить твой FINoM скрипт и чуть голову не сломал.

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

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

Одна цепь - один объект, все переменные в одном месте - искать не нужно, даже отладка проще.

x-yuri 23.12.2011 16:10

Цитата:

Сообщение от FINoM
Надоест, не надоест, более половины заказов по Javascript требуют использование jQuery. Так что выбор таков: потерять кучу денег из-за проблем, случающихся 1 раз на несколько тысяч строк кода, либо не выёбываться и работать.

выбор таков: 1) подстраиваться под "более половины заказов по Javascript требуют использование jQuery", 2) действовать по правилу правой руки, 3) выбирать инструменты исходя из задачи. Твои слова похожи на оправдание "Почему я использую jquery".

Анекдот такой есть. Первую неделю после получки стипендии у студента в столовой действует правило правой руки: закрываются цены - выбираются блюда. Вторую неделю дествует правило левой руки: закрываются блюда - выбираются цены. Далее действует правило буравчика: покрутился-повертелся и ушел.

ты не думаешь, что знание javascript, которое не просто знание jquery, лучше оплачивается? Да и вообще условия лучше.

Цитата:

Сообщение от FINoM
Мутулз — те же яйца

ни разу, почитай статью, которую я привел. И код сравни. Есть еще rightjs, но это наверное совсем андерграунд. Зато похоже на продолжение jquery + mootools.

Цитата:

Сообщение от FINoM
Эти функции семантичны. Из их названия сразу понятно, что они делают. А тут ситуация такая: хранить переменные, которые могут быть чем угодно (шириной, показателем мягкости, сочинением "как я провел лето").

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

Цитата:

Сообщение от Gozar
Ой, а я только сейчас заметил, что у меня получился вариант ну почти один в один как:

great minds think alike :)

FINoM 23.12.2011 17:29

Цитата:

Сообщение от x-yuri
ты не думаешь, что знание javascript, которое не просто знание jquery, лучше оплачивается?

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

Сообщение от x-yuri
ни разу

Да, возможно, я ошибаюсь. Но мутулз сейчас используется редко, как и прототайп.
Цитата:

Сообщение от x-yuri
потому что они работают с более конкретными вещами.

Может ты и прав. Сделаю ни тебе ни мне:
Init.prototype.data = function(item,value) {
  if(value === undefined) {return this.data[item]}
  else {this.data[item] = value}
}
Примерно так. Хочешь, используешь функции, хочешь, просто пишешь this.data.x = 2;
Цитата:

А лично моё мнение что FINoM усложняет реализацию.
Я пытался вынести почти всё в прототипы для лучшей читабельности, но получилась фигня. Попробую еще.

FINoM 23.12.2011 17:47

http://jsfiddle.net/XSGub/56/ — вот, вынес что мог в прототипы. Фигня в том, что когда вызывается runNext, он выполняется в контексте window. Заставлять писать кого-то runNext.call(this) — неправильно. A Function.prototype.bind слишком крупный, если хотим сделать кроссбраузерно.

FINoM 23.12.2011 17:49

Так что нужно обязательно замыкать callback в конструкторе. Есть идеи?

melky 23.12.2011 18:07

Цитата:

Сообщение от FINoM (Сообщение 145510)
какие есть альтернативы? Мутулз — те же яйца, прототайп — вырвиглазное говнище..

только бок у них более "объектно-ориентированный" и гибкий, хм...
правда, если рассматривать кверю не как функцию ($(selector).method()), а как объект ($.css(element, prop)), то гибкость повышается... но этот пост вообще не об этом!

/* что такое JavascriptMVC ? кто может вкратце обьяснить его суть? */

я погуглил насчёт альтернативы jquery и мне понравился qooxdoo. драг'н'дроп и другие плюшки их коробки.есть механизм поиска эл-ов по селектору (взят из Mootools). расскажите, что вы думаете об этом фреймворке библиотеке.

FINoM 23.12.2011 20:26

wait = function(first) {
        return new wait.Init(first);
    }

    wait.Init = function(first) {
        var self = this;
        this.callbackCaller = function() {
            self.callback.apply(self, arguments);
        }

        first.call(this, this.callbackCaller);
    }

    wait.Init.prototype = {
        deferred: [],
        callback: function() {
            this.args = [].slice.call(arguments);
            this.args.unshift(this.callbackCaller);
            if (this.deferred.length) {
                this.done = false;
                this.deferred[0].apply(this, this.args);
                this.deferred.shift();
            }
            if (!this.deferred.length) {
                this.done = true;
            }

        },

        wait: function(run) {

            if (this.done) {
                this.done = false;
                run.apply(this, this.args);

            } else {
                this.deferred.push(run);
            }
            return this;
        },
        data: function(item, value) {

            if (arguments.length === 2) {
                this.data[item] = value;
            } else {
                return this.data[item];
            }
        }
    }
Так и не придумал, как коллбек всунуть в прототип: http://jsfiddle.net/finom/XSGub/64/

x-yuri 23.12.2011 20:29

Цитата:

Сообщение от FINoM
Но мутулз сейчас используется редко, как и прототайп.

ну я понял, что для тебя важна популярность

Цитата:

Сообщение от FINoM
Так что нужно обязательно замыкать callback в конструкторе. Есть идеи?

извини, не хочется вникать в код

Цитата:

Сообщение от melky
/* что такое JavascriptMVC ? кто может вкратце обьяснить его суть? */

jquery done serious надстройка над jquery для разработки больших приложений, похоже, я не пробовал

Цитата:

Сообщение от melky
я погуглил насчёт альтернативы jquery и мне понравился qooxdoo. драг'н'дроп и другие плюшки их коробки.есть механизм поиска эл-ов по селектору (взят из Mootools). расскажите, что вы думаете об этом фреймворке библиотеке.

надо смотреть

FINoM 23.12.2011 20:34

Цитата:

Сообщение от x-yuri
ну я понял, что для тебя важна популярность

Мне важно сколько я на этом заработаю :D

--------------------------

Пытаюсь разобраться в backbonejs, смотрю примеры, понимаю как они работают, но не понимаю главного: зачем они так работают и как строить хваленные масштабные приложения с помощью сабжа. Может есть какие-нибудь статьи или книга "для чайников"?

x-yuri 23.12.2011 20:59

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

FINoM 23.12.2011 21:04

Цитата:

Сообщение от x-yuri
Наверное, это имеет смысл делать, когда у тебя скорее веб-приложение, чем сайт.

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

x-yuri 23.12.2011 22:43

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

FINoM 23.12.2011 23:54

Да, это веб приложение на одной странице.
Цитата:

Сообщение от x-yuri
А тесты должны помогать уменьшить количество ошибок при изменениях.

Юнит тестирование? Я так и не понял, как правильно их применять на таких проектах.
Цитата:

Сообщение от x-yuri
скорее всего ты слишком упрощаешь.

Наверно, особенно не глядя в код :)

melky 24.12.2011 00:25

Цитата:

Сообщение от x-yuri (Сообщение 145565)
jquery done serious надстройка над jquery для разработки больших приложений, похоже, я не пробовал

там вроде написано, что "если вы используете JSMVC и JQUERY в своих разработках, то вы можете повысить связанность между ними", но что это значит, неясно.
Цитата:

Сообщение от x-yuri (Сообщение 145581)

спасибо за линк на мою тему :) завтра посмотрю, сейчас немного не в адеквате

x-yuri 24.12.2011 00:53

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

Цитата:

Сообщение от FINoM
Юнит тестирование? Я так и не понял, как правильно их применять на таких проектах.

что значит как?

Цитата:

Сообщение от FINoM
Наверно, особенно не глядя в код

общение на форумах прокачивает скилл телепатии ;)

x-yuri 24.12.2011 00:59

Цитата:

Сообщение от melky
там вроде написано, что "если вы используете JSMVC и JQUERY в своих разработках, то вы можете повысить связанность между ними", но что это значит, неясно.

похоже не искаженную цитату

melky 24.12.2011 01:19

Цитата:

Сообщение от x-yuri (Сообщение 145637)
похоже не искаженную цитату

это фраза на русском, переведённая на русский, и сохранённая в моей голове :)

FINoM 24.12.2011 01:24

Цитата:

Сообщение от x-yuri
что значит как?

Покажи более-менее крупный проект с тестами, если есть.

x-yuri 24.12.2011 09:07

Цитата:

Сообщение от melky
это фраза на русском, переведённая на русский, и сохранённая в моей голове

ну тогда найди источник и процитируй. Русские термины в данном случае довольно странные и похожи друг на друга. Есть связанность (coupling), которая показывает, насколько элементы зависят друг от друга. А есть связность (cohesion), которая показывает, насколько сфокусированы обязанности элемента. В идеале каждый элемент должен выполнять свою определенную задачу, а не быть просто свалкой функциональности. Поэтому стремятся понизить связанность, и повысить связность.

Цитата:

Сообщение от FINoM
Покажи более-менее крупный проект с тестами, если есть.

могу предложить разве что посмотреть исходники каких-нибудь cms'ок, например, django, rails, django cms, typo blog. Либо самому поискать что-то подобное. На ruby по идее обычно все тестируют. Может там и для клиентской стороны что-то будет. Спроси DjDiablo, я сам пытался от него этого добиться. И нет, я еще не писал тесты. Если что-то найдешь/выяснишь, можешь сообщить, мне самому интересно. Мою тему еще можешь глянуть.

x-yuri 24.12.2011 13:34

Цитата:

Сообщение от FINoM
Может ты и прав. Сделаю ни тебе ни мне:

Init.prototype.data = function(item,value) {
  if(value === undefined) {return this.data[item]}
  else {this.data[item] = value}
}

Цитата:

Сообщение от FINoM
Примерно так. Хочешь, используешь функции, хочешь, просто пишешь this.data.x = 2;

кстати, это бессмысленно. У меня только одно замечание - оно не сделано в виде объекта. Все остальное - детали, которые ни на что не влияют.

FINoM 24.12.2011 23:25

Цитата:

Сообщение от x-yuri
кстати, это бессмысленно.

Хм, я всё это время пытался это доказать :D
Цитата:

Сообщение от x-yuri
У меня только одно замечание - оно не сделано в виде объекта.

Что ты имеешь в виду? data — это функция и, по совместительству, — объект.
Цитата:

Сообщение от x-yuri
Мою тему еще можешь глянуть.

Ок, гляну.

Gozar 25.12.2011 01:48

data не нужна.

FINoM 25.12.2011 02:51

Цитата:

data не нужна.
Ну а зачем мне тут кричали, что это обязательно?

x-yuri 25.12.2011 09:17

я говорил о data как об аргументе для перехода от функции к объекту. Потому что этот data будет странно смотреться в твоей реализации.

Цитата:

Сообщение от FINoM
Что ты имеешь в виду? data — это функция и, по совместительству, — объект.

по сути, у тебя функция, потому что вызывается так:
wait(function() {...})...

а у меня объект, потому что вызывается так:
new AsyncChain(...).add(function() {...})...

FINoM 25.12.2011 20:15

x-yuri, я тебя не понимаю.
Цитата:

Сообщение от x-yuri
по сути, у тебя функция, потому что вызывается так:

Цитата:

Сообщение от x-yuri
а у меня объект, потому что вызывается так:

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

x-yuri 26.12.2011 13:53

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

И нету смысла делать так, как я сказал. Ты должен сам видеть необходимость. Если не видишь - делай по-своему.

Еще раз, я тебе хотел сказать одну вещь: ты слишком упрощаешь, когда используешь функции, вместо объектов. Все. Необходимость хранить состояние - это всего лишь аргумент в пользу использования объектов.

x-yuri 26.12.2011 20:57

давайте все же расмотрим конкретный пример: ресайз картинок на клиенте с помощью flash.

Например, есть форма изменения юзерпика, в которой пользователь выбирает изображение. В результате появляется диалоговое окно, в котором пользователь указывает, как надо обрезать это изображение. Нажимает "Ok" диалогового окна, потом кнопку "Сохранить" формы. Получается что-то типа:
var chain = new AsyncChain();
$('jsChangeUserpicForm-eUserpicField').addEvent('change',   // input type="file"
    chain
        .setOptions({
            onFailure: function() {
                // показать пользователю сообщение об ошибке
                this.fireEvent('complete');
            },
            onComplete: function() {
                new Button('jsChangeUserpicForm-eAttachFileLink')
                    .enable();
                $('jsChangeUserpicForm-eAttachFileThrobber')
                    .addClass('sInvisible');
                this.state('cropResizeUserpicDialog')
                    && this.state('cropResizeUserpicDialog').close();
            }
        })
        .add(function() {
            new Button('jsChangeUserpicForm-eAttachFileLink')
                .disable();
            $('jsChangeUserpicForm-eAttachFileThrobber')
                .removeClass('sInvisible');
        })
        .add(function(NEXT) {
            sendForm({
                form: 'jsChangeUserpicForm',
                url: '/upload/userpic',
                onSuccess: function(userpicURL) {
                    chain.state('userpicURL', userpicURL);
                    NEXT();
                },
                onFailure: function() {
                    chain.fireEvent('failure');
                }
            });
        })
        .add(function(NEXT) {
            this.state('cropResizeUserpicDialog', new CropResizeUserpicDialog({
                userpicURL: chain.state('userpicURL'),
                dstWidth: 100,
                dstHeight: 100,
                onOk: function(cropX, cropY, cropWidth, cropHeight, resizeWidth, 

resizeHeight) {
                    this.state({
                        cropX: cropX,
                        cropY: cropY,
                        cropWidth: cropWidth,
                        cropHeight: cropHeight,
                        resizeWidth: resizeWidth,
                        resizeHeight: resizeHeight
                    });
                    NEXT();
                },
                onCancel: function() {
                    chain.fireEvent('complete');
                }
            }));
        })
        .add(function() {
            this.state('cropResize', new CropResize());
            this.state('cropResize').load(this.state('userpicURL'), {
                onSuccess: function() {
                    NEXT();
                },
                onFailure: function() {
                    chain.fireEvent('failure');
                }
            });
        })
        .add(function() {
            this.state('cropResize')
                .crop(
                    this.state('cropX'),
                    this.state('cropY'),
                    this.state('cropWidth'),
                    this.state('cropHeight')
                )
                .resize(
                    this.state('resizeWidth'), this.state('resizeHeight'),
                )
                .save({
                    url: '/upload/thumb',
                    onSuccess: function() {
                        NEXT();
                    },
                    onFailure: function() {
                        chain.fireEvent('failure');
                    }
                });
        })
        .add(function() {
            if ($('jsChangeUserpicForm-eUserpicURLField')) {
                var eUserpicURLField = $('jsChangeUserpicForm-eUserpicURLField');
            } else {
                var eUserpicURLField = new Element({
                    id: 'jsChangeUserpicForm-eUserpicField',
                    type: 'hidden'
                });
                eUserpicURLField.inject('jsChangeUserpicForm');
            }
            eUserpicURLField.name = 'userpic-url';
            eUserpicURLField.value = this.state('userpicURL');

            $('jsChangeUserpicForm-eUserpicThumb').src = this.state('userpicURL');
        });
);

дополнительные преимущества:
1) возможность научить addEvent запускать цепочки в ответ на событие;
2) предоставление интерфейса для работы с состоянием позволяет повторно использовать цепочку - для этого надо перед запуском цепочки очистить состояние; если пользователь сам придумывает, где хранить состояние, нету возможности его очистить;
3) возможность организовать аналогию блока finally из try-catch (событие complete).

p.s. это я называю конкретным примером. Наличие кода необязательно в общем-то, но в твоем примере с гипотетическим парсером непонятно даже какие действия составляют цепочку, не говоря уже о данных, составляющих состояние цепочки. Т.е. не хватает важной информации.

x-yuri 27.12.2011 00:04

Цитата:

Сообщение от FINoM
Пытаюсь разобраться в backbonejs, смотрю примеры, понимаю как они работают, но не понимаю главного: зачем они так работают и как строить хваленные масштабные приложения с помощью сабжа. Может есть какие-нибудь статьи или книга "для чайников"?

попробовал привлечь DjDiablo к этому вопросу в этой теме

FINoM 27.12.2011 01:39

Цитата:

Сообщение от x-yuri
1) возможность научить addEvent запускать цепочки в ответ на событие;

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

Сообщение от x-yuri
onFailure

Тоже круто, только
Цитата:

Сообщение от x-yuri
// показать пользователю сообщение об ошибке
                this.fireEvent('co mplete');

вот этого я не понял. Не смотря на опечатку (вместо 'complete' наверно должно быть 'failure') чем является this? Это контекст события?

Цитата:

Сообщение от x-yuri
 onComplete:

Зачем оно? Можно ведь в последнюю функцию запихать.
Цитата:

Сообщение от x-yuri
предоставление интерфейса для работы с состоянием позволяет повторно использовать цепочку - для этого надо перед запуском цепочки очистить состояние; если пользователь сам придумывает, где хранить состояние, нету возможности его очистить;

Ну только сейчас догнал, где оно может примениться.
Цитата:

Сообщение от x-yuri
непонятно даже какие действия составляют цепочку

Как же не понятно? Там ведь простые функции.
Цитата:

Сообщение от x-yuri
не говоря уже о данных, составляющих состояние цепочки

В примере состояния просто-напросто не нужны. Функции выполняются строго по-порядку, используя какую-то переменную из предыдущего вызова, если таковая есть. Того, что я предложил в начале достаточно для 90% задач, использующих асинхронные очереди.

x-yuri 27.12.2011 16:36

Цитата:

Сообщение от FINoM
Это круто. Только пока не понимаю, как грамотно и удобно возвращать и вызывать функцию. Наверно, идея гозара с методом, запускающим цепочку пойдет.

какую функцию? Метод, запускающий цепочку, вызывает addEvent

Цитата:

Сообщение от FINoM
вот этого я не понял. Не смотря на опечатку (вместо 'complete' наверно должно быть 'failure') чем является this? Это контекст события?

там должно быть именно complete. Цепочка не знает, когда должны происходить эти события. Это задача использующего кода. Это же событие запускается если пользователь передумал, нажал "Отмена" в диалоге. this обычно указывает на объект-источник события, в частности в данном случае.

Цитата:

Сообщение от FINoM
Зачем оно? Можно ведь в последнюю функцию запихать.

и как ты отмену собираешься обрабатывать? Напиши свою версию этого кода

Цитата:

Сообщение от FINoM
Ну только сейчас догнал, где оно может примениться.

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

Цитата:

Сообщение от FINoM
Как же не понятно? Там ведь простые функции.

Простые ничего полезного не делающие, ничего не обозначающие функции. У тебя абстрактный пример.

Цитата:

Сообщение от FINoM
В примере состояния просто-напросто не нужны. Функции выполняются строго по-порядку, используя какую-то переменную из предыдущего вызова, если таковая есть. Того, что я предложил в начале достаточно для 90% задач, использующих асинхронные очереди.

Что нужно в примере непонятно. Он может показать, как пользоваться твоей функцией. Но по нему нельзя сказать, достаточно ли функционала у твоей функции. Задача либо абстрактная, либо недостаточно подробно описана.

Цитата:

Сообщение от FINoM
Того, что я предложил в начале достаточно для 90% задач, использующих асинхронные очереди.

ну раз ты так говоришь, тогда я действительно зря усложняю :) А что ты будешь делать, когда ты столкнешься с этими 10% задач? Будешь добавлять костыли к своему решению? Или перепишешь его со всем использующим кодом?

FINoM 27.12.2011 17:15

Цитата:

Сообщение от x-yuri
какую функцию? Метод, запускающий цепочку, вызывает addEvent

Обычный запуск цепочки:
chain.add(...).add(...).run()
Запуск по событию:
doc.addEventListener(event, chain.add(...).add(...).run);
В первом случае мы сами вызываем функцию, во втором, передаем функцию для запуска после отлова события.
Цитата:

Сообщение от x-yuri
this обычно указывает на объект-источник события, в частности в данном случае.

Не понял фразы.
Цитата:

Сообщение от x-yuri
и как ты отмену собираешься обрабатывать? Напиши свою версию этого кода

Вместо
chain.setOptions({
   onComplete: function(){blabla()}
}).add(function first(){}).add(function second(){})

писать
chain.add(function first(){}).add(function second(){}).add(function() blabla()})

Цитата:

Сообщение от x-yuri
я это применение придумал, когда писал этот пример. Добавление состояния ничего не усложняет, и как видим ему нашлось применение.

А где хранить состояние? В замкнутом объекте? В смысле, чтоб пользователь не имел к нему доступа напрямую.
Цитата:

Сообщение от x-yuri
Простые ничего полезного не делающие, ничего не обозначающие функции. У тебя абстрактный пример.

Блин, чем тебе пример не нравится. Или ты предлагаешь заменить функции на существующие? Какая разница, если суть от этого не изменится? Давай так: ты работал с нодой?
Цитата:

Сообщение от x-yuri
Что нужно в примере непонятно. Он может показать, как пользоваться твоей функцией. Но по нему нельзя сказать, достаточно ли функционала у твоей функции. Задача либо абстрактная, либо недостаточно подробно описана.

То же самое. Задача описана для тех, кто знает, что такое серверный асинхронный JS.
Цитата:

Сообщение от x-yuri
А что ты будешь делать, когда ты столкнешься с этими 10% задач? Будешь добавлять костыли к своему решению? Или перепишешь его со всем использующим кодом?

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

x-yuri 27.12.2011 19:07

Цитата:

Сообщение от FINoM
Обычный запуск цепочки:
chain.add(...).add(...).run()
Запуск по событию:
doc.addEventListener(event, chain.add(...).add(...).run);
В первом случае мы сами вызываем функцию, во втором, передаем функцию для запуска после отлова события.

зачем, если можно научить addEvent работе с цепочками? Передаем ей цепочку, а она сама вызывает run.

Цитата:

Сообщение от x-yuri
this обычно указывает на объект-источник события, в частности в данном случае.

Цитата:

Сообщение от FINoM
Не понял фразы.

что в js, что в mootools, this в обработчике указывает на объект, который сгенерировал событие. Моя реализация следует этому соглашению. И jquery тоже.

Цитата:

Сообщение от FINoM
Вместо
chain.setOptions({
onComplete: function(){blabla()}
}).add(function first(){}).add(function second(){})

писать
chain.add(function first(){}).add(function second(){}).add(function() blabla()})

да, удобнее приводить такие вот схематические примеры, которые скрывают недостатки. Должно было быть так:
chain.setOptions({
    onComplete: function() {
        // выполняем завершающие действия
    }
}).add(function() {
    this.fireEvent('complete');
}).add(function() {
    // делаем что-то еще
}).add(function() {
    // делаем что-то еще
});

chain
    .add(function() {
        runNext(true);
    })
    .add(function(ignore) {
        if ( ! ignore) {
            // делаем что-то еще
        }
        runNext(ignore);
    })
    .add(function(ignore) {
        if ( ! ignore) {
            // делаем что-то еще
        }
        runNext(ignore);
    })
    .add(function(ignore) {
        if (ignore) {
            // выполняем завершающие действия
        }
    });


Цитата:

Сообщение от FINoM
А где хранить состояние? В замкнутом объекте? В смысле, чтоб пользователь не имел к нему доступа напрямую.

если пользователь что-то делает напрямую, либо он знает, что делает, либо ССЗБ

Цитата:

Сообщение от FINoM
Блин, чем тебе пример не нравится. Или ты предлагаешь заменить функции на существующие? Какая разница, если суть от этого не изменится? Давай так: ты работал с нодой?

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

Цитата:

Сообщение от FINoM
То же самое. Задача описана для тех, кто знает, что такое серверный асинхронный JS.

задача не описана, описана проблема. По проблеме нельзя судить о том, достаточно функциональности у твоей функции или нет.

Цитата:

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

хорошо, давай посмотрим на то, что есть и на то, что будет:
$('userpic').addEvent('change',   // input type="file"
    function() {
        chain
            .add(function(runNext) {
                $('attach-file').addClass('disabled');
                $('attach-file-throbber')
                    .removeClass('invisible');

                sendForm({
                    form: 'change-userpic-form',
                    url: '/upload/userpic',
                    onSuccess: function(userpicURL) {
                        runNext(false, userpicURL);
                    },
                    onFailure: function() {
                        runNext(true);
                    }
                });
            })
            .add(function(runNext, failure, userpicURL) {
                if (failure) {
                    runNext(true);
                }
                var cropResizeUserpicDialog = new CropResizeUserpicDialog({
                    userpicURL: userpicURL,
                    dstWidth: 100,
                    dstHeight: 100,
                    onOk: function(cropX, cropY, cropWidth, cropHeight, resizeWidth, resizeHeight) {
                        runNext(false, false, userpicURL, cropResizeUserpicDialog, cropX, cropY, cropWidth, cropHeight, resizeWidth, resizeHeight);
                    },
                    onCancel: function() {
                        runNext(true);
                    }
                }));
            })
            .add(function(runNext, ignore, failure, userpicURL, cropResizeUserpicDialog, cropX, cropY, cropWidth, cropHeight, resizeWidth, resizeHeight) {
                if (ignore) {
                    runNext(true);
                }
                if (failure) {
                    runNext(false, true);
                }
                var cropResize = new CropResize();
                cropResize.load(userpicURL, {
                    onSuccess: function() {
                        runNext(false, false, userpicURL, cropResizeUserpicDialog, cropX, cropY, cropWidth, cropHeight, resizeWidth, resizeHeight, cropResize);
                    },
                    onFailure: function() {
                        runNext(false, true);
                    }
                });
            })
            .add(function(runNext, ignore, failure, userpicURL, cropResizeUserpicDialog, cropX, cropY, cropWidth, cropHeight, resizeWidth, resizeHeight, cropResize) {
                if (ignore) {
                    runNext(true);
                }
                if (failure) {
                    runNext(false, true);
                }
                cropResize
                    .crop(cropX, cropY, cropWidth, cropHeight)
                    .resize(resizeWidth, resizeHeight)
                    .save({
                        url: '/upload/thumb',
                        onSuccess: function() {
                            runNext(false, false, userpicURL, cropResizeUserpicDialog);
                        },
                        onFailure: function() {
                            runNext(true);
                        }
                    });
            })
            .add(function(failure, userpicURL, cropResizeUserpicDialog) {
                if (failure) {
                    // показать пользователю сообщение об ошибке
                } else {
                    if ($('userpic-url')) {
                        var usrpicUrl = $('userpic-url');
                    } else {
                        var usrpicUrl = new Element({
                            id: 'userpic-url',
                            type: 'hidden'
                        });
                        usrpicUrl.inject('change-userpic-form');
                    }
                    usrpicUrl.name = 'userpic-url';
                    usrpicUrl.value = userpicURL;

                    $('eUserpicThumb').src = userpicURL;
                }

                $('attach-file').removeClass('disabled');
                $('attach-file-throbber')
                    .addClass('invisible');
                cropResizeUserpicDialog
                    && cropResizeUserpicDialog.close();
            });
    }
);


p.s. ты либо специально скрываешь недостатки, либо... не специально. И даже если мое решение требуется в исключительных случаях... чем твое решение лучше существующих для ноды?

FINoM 27.12.2011 19:49

Цитата:

Сообщение от x-yuri
зачем, если можно научить addEvent работе с цепочками? Передаем ей цепочку, а она сама вызывает run.

Ну а если мы хотим вызвать цепочку, то получится так: ...add().add().add()() ← видишь?
Цитата:

Сообщение от x-yuri
this в обработчике указывает на объект, который сгенерировал событие. Моя реализация следует этому соглашению.

Ты же хочешь использовать всякие вещи, типа this.state в функциях. Получается, что в обработчиках (oncomplete, onfailure) this будет элементом из события (в случае прямого запуска это будет window), а в функциях из цепочки this будет являться объектом chain?
Цитата:

Сообщение от x-yuri
Должно было быть так

Кто определяет как должно быть?
Цитата:

Сообщение от x-yuri
Приведи хотя бы какой-нибудь реальный пример, в котором видно, какие выполняются действия и какие передаются даныне.

Блин, привел же.
Цитата:

Сообщение от x-yuri
У нас тут в теме пользователь ноды, который вообще не видит проблемы.

Значит для него вложенные вызовы — это нормально.
Цитата:

Сообщение от x-yuri
задача не описана, описана проблема.

Описана задача сделать этот код более плоским.
Цитата:

Сообщение от x-yuri
чем твое решение лучше существующих для ноды?

Каких именно? Приведи хотя-бы одно.


Часовой пояс GMT +3, время: 14:57.