Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ns.modelCollection не поддерживает разреженные данные #161

Closed
wants to merge 16 commits into from

Conversation

chestozo
Copy link
Member

Вот такой вот пример:

var col = ns.Model.get('collection', {});
col.insert( [1, 2], 2 );

Приведёт к такому массиву элементов:

[ 1, 2 ]

Ожидаю:

[ undefined, undefined, 1, 2 ]

Это by design?
/cc @edoroshenko @doochik

@edoroshenko
Copy link
Contributor

Поговорили голосом. Роман решил сделать заход на поддержку разреженных коллекций

@chestozo
Copy link
Member Author

Краткое содержание изменений:

  1. метод insert теперь умеет вставлять разреженно данные:
// было
[ m1, m2 ]
insert( [m4, m5], 3 );
// стало
[ m1, m2, undefined, m4, m5 ]
// важно: insert вставляет:
insert(m3, 2);
[ m1, m2, m3, undefined, m4, m5 ]
// Чтобы установать элемент (с заменой) нужно использовать setModels()
  1. добавлен метод ns.ModelCollection.prototype.setModels = function(models, index).
    Данный метод нужен для установки элементов коллекции (с затиранием).
// было
[ m1, m2 ]
setModels( [m4, m5], 3 );
// стало
[ m1, m2, undefined, m4, m5 ]
// и главное:
setModels(m3, 2);
[ m1, m2, m3, m4, m5 ]
  1. Пустые элементы во viewCollection рендерятся на ряду с готовыми элементами коллекции.
    Для них создаются фейковые вьюхи ns-collection-item-fake (название можно поправить).

@chestozo
Copy link
Member Author

А ещё может переименовать для единообразия:
insert - insertItems
remove - removeItems
и тогда:
setModels - setItems
?
Я могу пока оставить insert и remove как алиасы...

@chestozo
Copy link
Member Author

  • переименовал setModels в setItems
  • добавил метод unsetItems (аналог remove, но оставляет дыру и не схлопывает её)
  • setItems вызывает unsetItems для затираемых элементов коллекции

@edoroshenko
Copy link
Contributor

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

@chestozo
Copy link
Member Author

Практическая задача может быть такая например:

  • у меня есть альбом с 1000 фоток
  • есть страница просмотра этого альбома (тумбнейлы фоток из альбома)
  • пользователь гуляет по страницам альбома
  • на 3ей странице ему нравится фотка и он в неё тыкает
  • открывается страница просмотра и слайдер с фотками из альбома
  • в слайдере я покажу только фотки с 3ей страницы
  • к примеру, он закрывает страницу просмотра и опять гуляет по альбому
  • на 7ой странице опять нажимает на фото
  • открывается страница просмотра со слайдером, в слейдере 7ая страница с фотками и 3яя где-то в глубине слайдера
  • между 3ей и 7ой - дыра (неподгруженные данные)

@chestozo
Copy link
Member Author

Итоговый changelog такой:

  • новый метод modelCollection.setItems(models, index=)
  • новый метод modelCollection.unsetItems(models, index=)
  • новое свойство в декларации viewCollection - split.empty_view_id. Если оно указано, для пустых элементов коллекции будут рендериться view этого типа. Если не указано - пустые модели не рендерятся вообще.

model.eventListeners[this.key] = this;

// если ранее мы не переопределяли прототипный тригер
// то переопеделим его
// XXX это очень жёсткий bad practice... Лучше модэли элементы коллекции тогда наследовать от какого-то ns.Model.CollectionItem, где всё это прописать.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

почему bad practice?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Потому что модель могла уже как-то переопределить этот метод и здесь это переопределение может затереться.

Самое лучше — сделать базовый тип ns.ModelCollectionItem где и переопределить trigger.
И добавить проверку, что подмодель наследуется от ns.ModelCollectionItem.

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

@edoroshenko
Copy link
Contributor

С названиями методов в корне не согласен. Получается:
insert(items, index)
setItems(items, index)
По имени метода невозможно понять, что он делает.
Метод insert реализует какую-то странную логику с раздвиганием.
unsetItems - непонятное название, а когда читаешь комметарий - становится ещё непонятнее. Где связть между unsetItems и "затиранием"? "Затирание" - это м.б. replace, но никак не unset.

Нужно хорошо проработать API, иначе все будут вечно путаться.

@edoroshenko
Copy link
Contributor

split.empty_view_id - плохо.
Правильный подход (который используется для других похожих случаев) - это специальное свойство в декларации view, на которое матчится отдельный шаблон. Пример - см. как работает async и placeholder.

} else {
itemViewId = split.view_id;
itemParams = no.extend({}, params, model.params);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Этот блок кода - корявый костыль, который ещё и дублируется.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Это правда, но пока мне показалось легче оставить так. Могу поправить.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

@edoroshenko
Copy link
Contributor

Ром, ещё раз, почему ты не хочешь создать пустые модели и по ним отрендерить вьюшки? Мы так делаем и всё отлично работает. Ты вместо того, чтобы использовать практику, которая уже где-то используется, искривляешь API и усложняешь логику работы.
Можно даже сделать так, чтобы пустые модели создавала сама modelCollection при вставке с "дыркой". И тогда всё будет работать ровно и просто.
Даже с точки зрения "правильности" этот подход лучше, потомучто ты создаёшь модели объектов, которые физически существуют. Просто их данные ещё не приехали с сервера

@chestozo
Copy link
Member Author

Ох, многовато комментов, сложно отвечать.
Отвечу кратко, детально можно при встрече поговорить.

  1. Названия методов.
    insert, кмк, надо переименовать в insertItems (для единообразия)
    Логика раздвигания - ровно та, которая и была, я её не менял.
    unsetItems я выбрал как антипод setItems
    replace в данном случае хуже, потому что по факту я затираю элементы, а не заменяю

split.empty_view_id - плохо.
Правильный подход (который используется для других похожих случаев) - это специальное свойство в декларации view, на которое матчится отдельный шаблон. Пример - см. как работает async и placeholder.

Тут ничего не понял.
empty_view_id сделано вот так:

ns.View.define('collection', {
  params: {},
  models: {},
  split: {
    view_id: 'item-view',
    empty_view_id: 'empty-item-view'
  }
});

Что в этом плохо - не понимаю.

@chestozo
Copy link
Member Author

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

Есть 2 варианта: делать фейковые модели и не делать их.
Чем лучше создавать фейковую модель в сравнении с тем, чтобы не создавать её вообще?

Где я искривляю API я не понял.

@edoroshenko
Copy link
Contributor

Чем лучше создавать фейковую модель в сравнении с тем, чтобы не создавать её вообще?

Тем, что не нужно обрабатывать её отсутствие. Логика будет проще

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

@chestozo
Copy link
Member Author

А чем логика пустой модели проще логики фейковой view?
Мне кажется специально создавать и добавлять кучу пустых моделей не лучше )

@edoroshenko
Copy link
Contributor

Проще тем, что viewCollection ничего не знает о том, что это какая-то особенная ситуация. Он просто работает со списком каких-то моделей.

@chestozo
Copy link
Member Author

Это так да.
Но зато ты снаружи коллекции должен об этом помнить и в нужный момент подменять пустые модели на настоящие.
И если тебе потребуется аналогичная коллекция - нужно будет это написать ещё раз. Ну или сразу сделать обёртку над коллекцией.

А с фейковыми вью не нужна обёртка, коллекция сама вставляет пустое вью на место дырки в данных.
А когда данные появятся - вставит туда нормальное view.

@edoroshenko
Copy link
Contributor

Вид должен содержать только логику рисования моделей.
Давай подумаем о том, чтобы пустые модели создавала/заменяла ns.ModelCollection

@chestozo
Copy link
Member Author

С фейковыми моделям есть одна засада: они совсем фейковые.
Это не незагруженная модель, это реальная заглушка.
Потому что не всегда ты знаешь параметры для создания этих пустых моделей.
А значит потом эту модель прийдётся полностью выкинуть и вставить новую.

У твоего варианта (чтобы пустые модели создавала/заменяла ns.ModelCollection) есть конечно плюс — не надо усложнять viewCollection.
Но, кмк, он не сильно усложнился ) судя по диффу. Надо только дублирование куска с проверкой существования модели пофиксить )

@chestozo
Copy link
Member Author

И тут я понял, что ты, скорее всего, прав ) ...
Буду смотреть дальше )

@chestozo
Copy link
Member Author

Поговорили голосом:

  • методы setItems / unsetItems не нужны
  • добавляем метод replace(items, index), который заменяем элементы коллекции
  • viewCollection перестаёт знать о том, что в modelCollection могут быть дыры в данных
  • ну и дыр в данных в modelCollection тоже больше не должно быть

Ещё вот надо подумать про:

  • создавать пустые элементы коллекции внутри коллекции
  • научить коллекцию саму запрашивать данные

@edoroshenko
Copy link
Contributor

тут бы ещё вот о чём подумать: м.б. добавить модели статус empty? А то {empty: true} - это могут быть реальные данные...
При этом, она должна считаться валидной

@edoroshenko
Copy link
Contributor

а на такой статус можно завязаться во viewCollection, и генерить такие декларации, на которые можно было бы матчиться в стандартном шаблоне.
Чтобы если ты сделал insert с дыркой и у тебя нет спец. шаблона для пустого view, у тебя всё работало правильно.

Conflicts:
	src/ns.modelCollection.js
@chestozo
Copy link
Member Author

В общем: переделал у себя на текущую версию modelCollection / viewCollection.
Думаю, пока можно всё оставить как есть, раз @edoroshenko собирается всё переделать ещё )

@chestozo chestozo closed this Nov 25, 2013
@chestozo
Copy link
Member Author

Больше всего мне не нравится в текущей версии, что:

  • надо руками создавать item-ы, которые грузятся (надо создавать fake-вые модели в коллекции)
  • когда подгрузились данные надо руками заменять fake на real модели в коллекции

@chestozo
Copy link
Member Author

И тут попалась нам коллекция из 5800 элементов.
И всё стало сильно тормозить.
В profile вижу такое:
profiling

В любом случае, создавать 5800 view довольно большой оверхед.
И тут вы скажите мне "а не создавай!"
Но я вам отвечу - а как?

Это слайдер с фотками, открыли мы первую фотку и подгрузили первые 20 фоток в слайдер (всё равно больше пока не видно).
Но нажал пользователь назад и надо его на самую последнюю фотку проводить.
И создать попутно все остальные фейковые.
И это тормозит.

@chestozo chestozo deleted the collection.disperse branch May 5, 2018 11:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants