-
Notifications
You must be signed in to change notification settings - Fork 39
/
05s-the-session.md.erb
157 lines (107 loc) · 12.1 KB
/
05s-the-session.md.erb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
---
title: Сессия
slug: the-session
date: 0005/01/02
number: 5.5
sidebar: true
contents: Познакомитесь с сессиями в Meteor|Узнаете о функции autorun|Поймете, как работает горячая замена кода
paragraphs: 33
---
Meteor - это реактивный фреймворк. Если в вашем коде или в любых других данных появились какие-либо изменения, то они применятся немедленно, без необходимости что-либо перезагружать или обновлять.
Мы уже видели этот механизм в действии, когда наши шаблоны обновлялись сразу после изменения данных и route.
Мы постараемся подробнее разобрать и понять, как это работает в следующих главах, но сейчас, мы бы хотели подробнее остановиться на некоторых основных "реактивных" функциях, которые используются повсеместно.
### Сессия в Meteor (The Meteor Session)
На данный момент текущее состояние приложения Microscope полностью отражается в адресе URL (и в базе данных).
Но бывают случаи, когда необходимо сохранить какое-либо состояние, которое относится только к конкретному пользователю приложения (например, сворачивание и разворачивание списков, диалогов и т.д). Сессия будет удобным способом решения этой проблемы.
Сессия является глобальным и быстрым хранилищем данных. Под глобальным, подразумевается глобальный singleton объект: есть одна сессия, и она доступна отовсюду. Использование глобальных переменных считается дурным тоном, но сессия сама по себе рассматривается как глобальное хранилище данных и используется в различных частях приложения.
### Изменение сессии (Changing the Session)
Сессия доступна отовсюду как `Session`. Чтобы установить какое-либо значение в сессии, необходимо сделать следующее:
~~~js
❯ Session.set('pageTitle', 'A different title');
~~~
<%= caption "Browser console" %>
Прочитать данные сессии можно, написав `Session.get('mySessionProperty');`. Это очень быстрое и удобное хранилище данных. Если вы напишете это в хелпер, то заметите, что вывод хелпера моментально меняется после изменения переменной сессии.
Чтобы проверить это, добавим следующий код в текст шаблона "layout":
~~~html
<header class="navbar">
<div class="navbar-inner">
<a class="brand" href="{{pathFor 'postsList'}}">{{pageTitle}}</a>
</div>
</header>
~~~
<%= caption "client/views/application/layout.html"%>
~~~js
Template.layout.helpers({
pageTitle: function() { return Session.get('pageTitle'); }
});
~~~
<%= caption "client/views/application/layout.js"%>
Meteor автоматически обновится (как мы уже знаем, это называется “горячее обновление кода” или HCR) сохраняя переменные сессии, так что теперь мы увидим новый заголовок "A different title" в панели навигации. Если ничего не произошло, то просто попробуйте набрать предыдущую команду `Session.set()` снова.
Более того, если мы изменим значение еще раз (снова набрав `Session.set()` в консоли браузера), то мы увидим новый заголовок:
~~~js
❯ Session.set('pageTitle', 'A brand new title');
~~~
<%= caption "Browser console" %>
Сессия доступна глобально, так что изменения могут быть внесены в любом месте приложения. Это дает нам больше возможностей, но также может и загнать в ловушку.
<% note do %>
### Идентичные изменения (Identical Changes)
Если вы записываете в переменную сессии (`Session.set()`) одно и тоже значение повторно, Meteor'у хватит ума, чтобы не запускать реактивные обновления и избежать ненужных вызовов функций.
<% end %>
### Введение в Autorun (Introducing Autorun)
Мы уже встречали пример реактивного источника данных и видели его в действии внутри хелпера шаблона. Хоть некоторые места в Meteor (такие, как хелперы шаблонов) и являются реактивными, львиная доля всего приложения - все еще простой не реактивный JavaScript.
Давайте предположим, что где-нибудь в нашем приложении у нас есть следующий фрагмент кода:
~~~js
helloWorld = function() {
alert(Session.get('message'));
}
~~~
Не смотря на то, что мы обращаемся к переменной сессии, *контекст*, в котором к ней обращались, не реактивен: мы не будем видеть новые `alert`'ы каждый раз после изменения переменной.
Тут на помощь приходит [Autorun](http://docs.meteor.com/#deps_autorun). Как подразумевает название, код внутри блока `autorun` автоматически выполнится и будет выполнятся каждый раз, когда реактивный источник данных, использованный внутри, будет изменен.
Попробуйте выполнить в браузерной консоли следующее:
~~~js
❯ Deps.autorun( function() { console.log('Value is: ' + Session.get('pageTitle')); } );
Value is: A brand new title
~~~
<%= caption "Browser console" %>
Как вы могли ожидать, блок кода, переданный в `autorun`, сработал один раз и вывел в консоль значение переменной. Теперь давайте попробуем изменить заголовок:
~~~js
❯ Session.set('pageTitle', 'Yet another value');
Value is: Yet another value
~~~
<%= caption "Browser console" %>
Магия! Как только значение переменной сессии изменилось, `autorun` узнал об этом и выполнил весь свой код снова, выведя новое значение в консоль.
Итак, возвращаясь к предыдущему примеру, если мы хотим показывать новый alert при каждом изменении переменной cессии, нам нужно лишь обернуть наш код в блок `autorun`.
~~~js
Deps.autorun(function() {
alert(Session.get('message'));
});
~~~
Как мы только что видели, autorun'ы могут быть очень полезными для отслеживания реактивных источников данных и обязательного реагирования на них.
### Горячее обновление кода (Hot Code Reload)
Пока мы разрабатывали наш Microscope, мы использовали одно из преимуществ Meteor, сберегающих время: горячее обновление кода (HCR). Всякий раз, когда мы сохраняем один из файлов исходников, Meteor замечает изменения и незаметно перезапускает работающий сервер Meteor, оповещая каждого клиента о необходимости обновить страницу.
Это очень похоже на автоматическое обновление страниц, но есть одно важное отличие.
Чтобы понять его, начнем изменять переменную сессии, которую мы использовали:
~~~js
❯ Session.set('pageTitle', 'A brand new title');
❯ Session.get('pageTitle');
'A brand new title'
~~~
<%= caption "Browser console" %>
Если мы обновим страницу в браузере вручную, наши переменные сессии будут потеряны (точнее, они будут созданы заново). Но если мы спровоцируем выполнение горячего обновления кода (например, сохранив один из файлов исходников), страница будет обновлена, а переменные сессии останутся прежними. Попробуйте!
~~~js
❯ Session.get('pageTitle');
'A brand new title'
~~~
<%= caption "Browser console" %>
Итак, если мы используем переменные сессии для хранения того, что делает пользователь, HRC будет полностью прозрачной для него, так как сохранит значения всех переменных сессии. Это позволяет нам загружать новую production-версию нашего Meteor-приложения, будучи уверенными в минимальных нарушениях работы клиента наших пользователей.
Рассмотрим это чуть подробней. Если мы будем хранить все состояния в URL и в сессии, то мы сможем прозрачно менять _запущенный код_ каждого клиента с минимальными потерями.
Давайте теперь проверим, что получится, если мы обновим страницу вручную:
~~~js
❯ Session.get('pageTitle');
null
~~~
<%= caption "Browser console" %>
Когда мы перезагрузили страницу, мы потеряли сессию. При HCR Meteor сохраняет сессию в local storage вашего браузера и загружает ее после обновления. Однако, при явной перезагрузке имеет смысл иное поведение: если пользователь обновляет страницу, как если бы он снова перешел по такому же URL, то данные должны быть сброшены к начальному состоянию, которое увидит любой пользователь, посетивший этот URL.
Самое важное в этой главе:
1. Всегда храните состояние пользователя в сессии или в URL, тогда HCR будет проходить с минимальными потерями.
2. Любое состояние, которое вы хотите разделить между пользователями, храните *внутри URL*.