Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Pagination Demystified

Pagination Demystified

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

Faf4a633b0d1e32a07a071039686c868?s=128

Egor Tolstoy

March 30, 2016
Tweet

Transcript

  1. PAGINATION DEMYSTIFIED Egor Tolstoy @igrekde

  2. DISCLAIMER ВЫСТУПЛЕНИЕ ОСНОВАНО НА ЛИЧНОМ СТРАДАНИЯХ ОПЫТЕ. ДОКЛАД СОДЕРЖИТ ДЕТАЛЬНОЕ

    ОПИСАНИЕ ОТВРАТИТЕЛЬНЫХ КОСТЫЛЕЙ И ПОЭТОМУ НЕ РЕКОМЕНДУЕТСЯ К ПРОСМОТРУ НИКОМУ.
  3. None
  4. None
  5. Локальная фильтрация Динамический размер страницы Пересобирается раз в час Выдача

    лежит на CDN Все еще limit/offset authorId = postId >> 32
  6. Техники пагинации Как подступиться Загрузка вниз Обновление ленты

  7. limit/offset httр://api.соm/entries?offset=100&limit=20

  8. 0 1 2 cache server 0 1 2 3 4

    5 6 7
  9. 0 1 2 cache server 0 1 2 3 4

    5 6 7 offset: 3 limit: 5 3 4 5 6 7
  10. 0 1 2 cache server 0 1 2 3 4

    5 6 7 offset: 3 limit: 5 3 4 5 6 7 3 4 5 6 7 3 4 5 6 7
  11. Номера страниц httр://api.соm/entries?page_number=3

  12. cache server 0 1 2 0

  13. cache server 0 1 2 0 page: 1 1

  14. cache server 0 1 2 0 page: 1 1 1

    2 1
  15. Позиции элементов не меняются Условия

  16. Курсоры httр://api.соm/entries?since=752284800&limit=10 httр://api.соm/entries? max_id=228&limit=10 httр://api.соm/entries? after=MTAxNTE&limit=10

  17. cache server 0 1 2 21:04- 21:02- 19:35- 19:18- 17:44-

    16:02- 15:58- 15:49- 15:40- 3 4 5 6 7 8 0 1 2 19:35- 19:18- 17:44- 15:21- 9
  18. cache server 0 1 2 21:04- 21:02- 19:35- 19:18- 17:44-

    16:02- 15:58- 15:49- 15:40- 3 4 5 6 7 8 0 1 2 19:35- 19:18- 17:44- since: 17:44 limit: 5 15:21- 9 3 4 5 6 7 16:02- 15:58- 15:49- 15:40- 15:21-
  19. cache server 0 1 2 21:04- 21:02- 19:35- 19:18- 17:44-

    16:02- 15:58- 15:49- 15:40- 3 4 5 6 7 8 0 1 2 19:35- 19:18- 17:44- since: 17:44 limit: 5 15:21- 9 3 4 5 6 7 16:02- 15:58- 15:49- 15:40- 15:21- 16:02- 15:58- 15:49- 15:40- 5 6 7 8 15:21- 9
  20. Уникальный параметр каждого элемента Сортировка выдачи не меняется Условия

  21. Изменение количества элементов Актуальность выдачи Обновление контента • Лента статична

    • Новые элементы добавляются сверху • Любая часть выдачи может быть изменена • Выдача всегда актуальна • Выдача может быть переформирована • Отображаемые данные не обновляются • Отображаемые данные могут быть изменены
  22. 1. Количество элементов не меняется 2. Выдача всегда актуальна 3.

    Данные могут быть изменены Афиша.Рестораны
  23. 1. Новые элементы добавляются только сверху 2. Выдача всегда актуальна

    3. Данные могут быть изменены Афиша
  24. 1. Количество элементов не меняется 2. Выдача может быть переформирована

    3. Данные не могут быть изменены Рамблер.Новости
  25. 1. Любая часть выдачи может быть изменена 2. Выдача всегда

    актуальна 3. Данные могут быть изменены Рамблер.Почта
  26. тем временем в офисе бэкенда

  27. Решения проблем пагинации на клиенте

  28. item 0 item 1 item 2 item 3 item 4

    item 5 item 6 item 7 item 8 item 9 Загрузка вниз Случай 1: Лента статична 1/5
  29. item 0 item 1 item 2 item 3 item 4

    item 5 item 6 item 7 item 8 item 9 offset: 0 limit: 5 Загрузка вниз Случай 1: Лента статична 2/5
  30. item 0 (cached) item 1 (cached) item 2 (cached) item

    3 (cached) item 4 (cached) item 5 item 6 item 7 item 8 item 9 offset: 0 limit: 5 Загрузка вниз Случай 1: Лента статична 3/5
  31. item 0 (cached) item 1 (cached) item 2 (cached) item

    3 (cached) item 4 (cached) item 5 item 6 item 7 item 8 item 9 offset: 0 limit: 5 offset: 5 limit: 5 Загрузка вниз Случай 1: Лента статична 4/5
  32. item 0 (cached) item 1 (cached) item 2 (cached) item

    3 (cached) item 4 (cached) item 5 (cached) item 6 (cached) item 7 (cached) item 8 (cached) item 9 (cached) offset: 0 limit: 5 offset: 5 limit: 5 Загрузка вниз Случай 1: Лента статична 5/5
  33. paging.startIndex = cachedPosts.count; paging.count = 5;

  34. item 0 (cached) item 1 (cached) item 2 (cached) item

    3 (cached) item 4 (cached) item 5 item 6 item 7 item 8 item 9 offset: 0 limit: 5 Загрузка вниз Случай 2: Добавились новые элементы 1/5
  35. item 0 (cached) item 1 (cached) item 2 (cached) item

    3 (cached) item 4 (cached) item 5 item 6 item 7 item 8 item 9 offset: 0 limit: 5 item 0' (new) item 2' (new) Загрузка вниз Случай 2: Добавились новые элементы 2/5
  36. item 0 (cached) item 1 (cached) item 2 (cached) item

    3 (cached) item 4 (cached) item 5 item 6 item 7 item 8 item 9 offset: 0 limit: 5 offset: 5 limit: 5 item 0' (new) item 2' (new) Загрузка вниз Случай 2: Добавились новые элементы 3/5
  37. item 0 (cached) item 1 (cached) item 2 (cached) item

    3 (cached) item 4 (cached) item 5 (cached) item 6 (cached) item 7 (cached) item 8 item 9 offset: 0 limit: 5 offset: 5 limit: 5 item 0' (new) item 2' (new) Загрузка вниз Случай 2: Добавились новые элементы 4/5
  38. item 0 (cached) item 1 (cached) item 2 (cached) item

    3 (cached) item 4 (cached) item 5 (cached) item 6 (cached) item 7 (cached) item 8 item 9 offset: 0 limit: 5 offset: 5 limit: 5 offset: 8 + 2 item 0' (new) item 2' (new) Загрузка вниз Случай 2: Добавились новые элементы 5/5
  39. paging.startIndex = cachedPosts.count + intersections; paging.count = 5;

  40. item 0 (cached) item 1 (cached) item 2 (cached) item

    3 (cached) item 4 (cached) item 5 item 6 item 7 item 8 item 9 offset: 0 limit: 5 Загрузка вниз Случай 3: Удалены старые элементы 1/7
  41. item 0 (cached) item 1 (cached) item 2 (cached) item

    3 (cached) item 4 (cached) item 5 item 6 item 7 item 8 item 9 offset: 0 limit: 5 item 10 item 11 Загрузка вниз Случай 3: Удалены старые элементы 2/7
  42. item 0 (cached) item 1 (cached) item 2 (cached) item

    3 (cached) item 4 (cached) item 5 item 6 item 7 item 8 item 9 offset: 0 limit: 5 item 10 item 11 offset: 5 limit: 5 Загрузка вниз Случай 3: Удалены старые элементы 3/7
  43. item 0 (cached) item 1 (cached) item 2 (cached) item

    3 (cached) item 4 (cached) item 5 item 6 item 7 (cached) item 8 (cached) item 9 (cached) offset: 0 limit: 5 item 10 (cached) item 11 (cached) offset: 5 limit: 5 Загрузка вниз Случай 3: Удалены старые элементы 4/7
  44. item 0 (cached) item 1 (cached) item 2 (cached) item

    3 (cached) item 4 (cached) item 5 item 6 item 7 item 8 item 9 offset: 0 limit: 5 ... Загрузка вниз Случай 3: Удалены старые элементы 5/7
  45. item 0 (cached) item 1 (cached) item 2 (cached) item

    3 (cached) item 4 (cached) item 5 item 6 item 7 item 8 item 9 offset: 0 limit: 5 ... offset: 4 limit: 5 Загрузка вниз Случай 3: Удалены старые элементы 6/7
  46. item 0 (cached) item 1 (cached) item 2 (cached) item

    3 (cached) item 4 (cached) item 5 (cached) item 6 (cached) item 7 (cached) item 8 (cached) item 9 offset: 0 limit: 5 ... offset: 4 limit: 5 Загрузка вниз Случай 3: Удалены старые элементы 7/7
  47. paging.startIndex = startIndex - 1; paging.count = 5;

  48. еще одна шутка про Facebook

  49. item 0 item 1 item 2 item 3 item 4

    item 5 item 6 item 7 item 8 item 9 Загрузка вниз Случай 4: Порядок выдачи пересобирается 1/5
  50. item 0 item 1 item 2 item 3 item 4

    item 5 item 6 item 7 item 8 item 9 items: 0,1,2,3,4 Загрузка вниз Случай 4: Порядок выдачи пересобирается 2/5
  51. item 0 (cached) item 1 (cached) item 2 (cached) item

    3 (cached) item 4 (cached) item 5 item 6 item 7 item 8 item 9 items: 0,1,2,3,4 Загрузка вниз Случай 4: Порядок выдачи пересобирается 3/5
  52. item 6 item 1 (cached) item 4 (cached) item 5

    item 8 item 9 item 2 (cached) item 0 (cached) item 7 item 3 (cached) Загрузка вниз Случай 4: Порядок выдачи пересобирается 4/5
  53. item 6 (cached) item 1 (cached) item 4 (cached) item

    5 (cached) item 8 (cached) item 9 (cached) item 2 (cached) item 0 (cached) item 7 (cached) item 3 (cached) items: 5,6,7,8,9 Загрузка вниз Случай 4: Порядок выдачи пересобирается 5/5
  54. NSRange pageRange = NSMakeRange(startIndex, 5); NSArray *postIds = [snapshot subarrayWithRange:pageRange];

  55. item 0 (new) item 1 (new) item 2 (new) item

    3 (new) item 4 (new) item 5 (new) item 7 (cached) item 8 (cached) item 9 (cached) item 6 (new) Обновление Случай 1: Появилось много новых элементов 1/3
  56. item 7 (cached) item 8 (cached) item 9 (cached) offset:

    0 limit: 5 item 0 (new) item 1 (new) item 2 (new) item 3 (new) item 4 (new) item 5 (new) item 6 (new) Обновление Случай 1: Появилось много новых элементов 2/3
  57. item 0 (cached) item 1 (cached) item 2 (cached) item

    3 (cached) item 4 (cached) item 5 (new) item 7 (cached) item 8 (cached) item 9 (cached) offset: 0 limit: 5 item 6 (new) Обновление Случай 1: Появилось много новых элементов 3/3
  58. if (intersections == 0) { [self dropCache]; }

  59. item 0 (cached) item 1 (cached) item 3 (cached) item

    4 (cached) item 6 (cached) item 7 (cached) item 8 (deleted) item 9 (cached) item 5 (new) item 2 (new) Обновление Случай 2: Свободно изменяемая лента 1/1
  60. for (ShortPost *post in diff) { [self updateCacheWith:post]; }

  61. for (ShortPost *post in snapshot) { if (![cachedPosts containsObject:post]) {

    [self downloadPost:post]; } } for (Post *post in cachedPosts) { if (![snapshot containsObject:post]) { [self deletePost:post]; } }
  62. item 6 item 1 (cached) item 4 (cached) item 5

    item 8 item 9 item 2 (cached) item 0 (cached) item 7 item 3 (cached) Обновление Случай 3: Порядок выдачи пересобирается 1/1
  63. NSString *lastModified = [self makeFeedHeadRequest]; if (![lastModified isEqual:cachedLastModified]) { [self

    dropCache]; [self obtainPostSnapshot]; [self obtainFirstPage]; }
  64. item 0 (cached) item 1 (updated) item 2 (cached) item

    3 (updated) item 4 (updated) item 5 item 6 item 7 item 8 item 9 Обновление Случай 4: Данные элементов меняются 1/1
  65. for (NSUInteger i = 0; i < cachedPosts.count; i++) {

    Post *cachedPost = cachedPosts[i]; ShortPost *post = snapshot[i]; if (![cachedPost isEqual:post]) { [cachedPost updatePostWithShortPost:post]; } }
  66. posts: NSArray <Post *> snapshot: NSArray <NSString *> offset: NSUInteger

    maxCount: NSUInteger lastModified: NSDate Feed
  67. PostService loadPosts didLoad Cache

  68. PostService loadPosts didLoad Cache

  69. CacheTracker PostService loadPosts didLoad Cache

  70. PagingFacade PostService ViewController FeedService CacheUpdater SnapshotProcessor PagingCalculator

  71. @protocol PostPagingFacade <NSObject> - (void)loadNextPageWithBlock:(ErrorBlock)block; - (void)refreshCategoryWithBlock:(ErrorBlock)block; - (void)reloadCategoryWithBlock:(ErrorBlock)block; @end

  72. Клиент должен быть простым

  73. Техники пагинации Как подступиться Загрузка вниз Обновление ленты

  74. Egor Tolstoy @igrekde не смог придумать заключительную фразу