Meteor 是一個(gè)響應(yīng)式框架。這意味著隨著數(shù)據(jù)的變化, App 的改變并不需要你顯式地做任何事情。
事實(shí)上,我們已經(jīng)看到過我們的模板是如何根據(jù)數(shù)據(jù)和路由規(guī)則的變化去進(jìn)行改變的。
我們將在后面的章節(jié)去深入了解這里面是如何工作的,但我們現(xiàn)在想介紹一些基本的響應(yīng)性功能,它對(duì)于普通的 App 是非常有用的。
現(xiàn)在在 Microscope 下,用戶在 App 中的當(dāng)前狀態(tài)是完全包含在 URL 里面,并且需要從 URL (或者數(shù)據(jù)庫(kù))里面尋找。
但是在許多情況下,你需要存儲(chǔ)一些只對(duì)應(yīng)于當(dāng)前用戶的應(yīng)用程序版本的短暫狀態(tài)(例如,一個(gè)元素是否顯示或隱藏)。利用 Session 可以很方便地去做到這一點(diǎn)。
Session 是一個(gè)全局的響應(yīng)式數(shù)據(jù)存儲(chǔ)。它全局性的意思是全局的單例對(duì)象:這個(gè) Session 對(duì)象在全局都是可被訪問到。全局變量通常被認(rèn)為不是一件什么好事,不過在剛才的例子上,Session 可以作為中央通信總線用于項(xiàng)目的不同地方。
會(huì)話 Session
是全局可訪問的。設(shè)置一個(gè) Session 的值,你可以調(diào)用:
? Session.set('pageTitle', 'A different title');
瀏覽器控制臺(tái)(Browser console)
通過 Session.get('mySessionProperty');
你可以重新讀取數(shù)據(jù)的內(nèi)容,這是一個(gè)響應(yīng)式的數(shù)據(jù)源,這意味著如果你把它放在一個(gè) Helper 里面,你會(huì)看到 Helper 根據(jù) Session 變量的改變而響應(yīng)式地改變它的輸出。
讓我們?cè)囈辉?,將下面的代碼添加到布局模板:
<header class="navbar navbar-default" role="navigation">
<div class="navbar-header">
<a class="navbar-brand" href="{{pathFor 'postsList'}}">{{pageTitle}}</a>
</div>
</header>
client/templates/application/layout.html
Template.layout.helpers({
pageTitle: function() { return Session.get('pageTitle'); }
});
client/templates/application/layout.js
請(qǐng)注意在附錄章節(jié)中的代碼并不是本書主流程的一部分。所以要么創(chuàng)建一個(gè)新分支(如果你使用 Git),要么確保在本章結(jié)束后恢復(fù)你所做的改動(dòng)。
Meteor 的自動(dòng)重載(即使用后面講到的“動(dòng)態(tài)代碼重載技術(shù)”(HCR)的頁面自動(dòng)刷新)會(huì)保存 Session 的變量,所以我們現(xiàn)在應(yīng)該看到“不同的標(biāo)題”顯示在導(dǎo)航欄中。如果不是,再次輸入之前的 Session.set()
命令。
另外,如果我們?nèi)ジ乃闹担ㄔ俅卧跒g覽器控制臺(tái)中),我們應(yīng)該看到另一個(gè)標(biāo)題顯示:
? Session.set('pageTitle', 'A brand new title');
Browser console
由于 Session 的全局可訪問性,所以這些變化可以作用到應(yīng)用程序的任何地方。這給了我們很大的權(quán)力,但如果使用太多也可以是一個(gè)陷阱。
另外,重點(diǎn)指出的是 Session 對(duì)象不在用戶之間共享,甚至在瀏覽器標(biāo)簽之間。這就是為什么如果現(xiàn)在你在新瀏覽器標(biāo)簽打開你的應(yīng)用,你會(huì)看到一個(gè)空網(wǎng)站標(biāo)題。
如果你通過 Session.set()
去修改一個(gè) Session 變量,并將其修改為相同的值,Meteor 會(huì)非常聰明的繞過繁瑣的操作,避免不必要的方法調(diào)用。
我們看到響應(yīng)式數(shù)據(jù)源的一個(gè)例子,并且看到了它在一個(gè)模板 Helper 里面的運(yùn)作。盡管某些情況下 Meteor(如模板 Helper)是響應(yīng)式的,但是大部分的 Meteor App 仍然是基于普通的非響應(yīng)式的 JavaScript 代碼。
讓我們假設(shè)有以下的代碼片段在我們的 App:
helloWorld = function() {
alert(Session.get('message'));
}
盡管我們調(diào)用一個(gè)響應(yīng)式會(huì)話(Session)變量,但它并不是在響應(yīng)式的上下文中調(diào)用,所以當(dāng)改變這個(gè) Session 變量的時(shí)候,我們也不會(huì)自動(dòng)運(yùn)行 alert
函數(shù)。
這個(gè)時(shí)候,就要引入自動(dòng)運(yùn)行(Autorun)機(jī)制了。顧名思義,每一次 autorun
上下文中的響應(yīng)式數(shù)據(jù)源發(fā)生變化的時(shí)候,autorun
函數(shù)就會(huì)自動(dòng)運(yùn)行。
嘗試到瀏覽器控制臺(tái)輸入:
? Tracker.autorun( function() { console.log('Value is: ' + Session.get('pageTitle')); } );
Value is: A brand new title
瀏覽器控制臺(tái)(Browser console)
如你所料,放在 autorun
函數(shù)里面的代碼將會(huì)運(yùn)行一次,把數(shù)據(jù)輸出到控制臺(tái)。現(xiàn)在,讓我們嘗試去改變標(biāo)題:
? Session.set('pageTitle', 'Yet another value');
Value is: Yet another value
瀏覽器控制臺(tái)(Browser console)
神奇吧!隨著 Session 變量的改變, autorun
知道它必須重新運(yùn)行自己的代碼,并把新的值重新輸出到控制臺(tái)。
所以我們回到之前的例子,如果希望每次 Session 變量發(fā)生變化的時(shí)候引發(fā)新的警報(bào)(alert
),我們需要做的就是將我們的代碼封裝在 autorun
函數(shù)里面:
Tracker.autorun(function() {
alert(Session.get('message'));
});
正如我們前面看到的,autorun
會(huì)自動(dòng)跟蹤響應(yīng)式數(shù)據(jù)源,在它們變化的時(shí)候作出響應(yīng)的反應(yīng)。
在 Microscope 的開發(fā)過程中,我們已經(jīng)用過 Meteor 的動(dòng)態(tài)代碼重載技術(shù)(HCR)去節(jié)省時(shí)間:當(dāng)我們修改并保存一個(gè)源代碼的文件后,Meteor 會(huì)立刻檢測(cè)到變化,直接重啟正在運(yùn)行的 Meteor 服務(wù)器,并通知每個(gè)客戶端重新加載該頁面。
這類似于頁面的自動(dòng)刷新,但有一個(gè)很重要的差異。
為了找出那是什么,先重置一下之前改過的 Session 變量:
? Session.set('pageTitle', 'A brand new title');
? Session.get('pageTitle');
'A brand new title'
瀏覽器控制臺(tái)(Browser console)
如果我們手動(dòng)去重載瀏覽器窗口,自然就會(huì)丟失我們的 Session 變量(因?yàn)檫@將會(huì)創(chuàng)建一個(gè)新的會(huì)話)。另一方面,如果我們是引發(fā)動(dòng)態(tài)代碼重載(即,通過修改并保存我們的源文件)去重新加載頁面,Session 變量卻仍然存在。現(xiàn)在去試一試!
? Session.get('pageTitle');
'A brand new title'
瀏覽器控制臺(tái)(Browser console)
因此,如果使用 Session 變量來保存用戶狀態(tài),用戶幾乎不會(huì)察覺到動(dòng)態(tài)代碼重載的發(fā)生。因?yàn)樗鼘⒈A羲?Session 變量的值。這可以使我們?cè)诓渴鹦掳姹镜臅r(shí)候,用戶發(fā)生中斷的機(jī)會(huì)降到最低。
再想一想,這意味著,只要我們做到用 URL 和 Session 把所有狀態(tài)保存下來,那么當(dāng)更新版本的時(shí)候,客戶端正在運(yùn)行的應(yīng)用程序就可以動(dòng)態(tài)重載,不丟失任何數(shù)據(jù)。
現(xiàn)在去檢驗(yàn)一下當(dāng)我們?nèi)ナ謩?dòng)刷新頁面的時(shí)候發(fā)生了什么:
? Session.get('pageTitle');
null
瀏覽器控制臺(tái)(Browser console)
當(dāng)我們重載頁面時(shí),我們丟失了 Session 。在 HCR 中,Meteor 將 Session 保存到瀏覽器的本地存儲(chǔ)并且在重載的之后再一次加載它。然而,在重載頁面時(shí)發(fā)生的丟失行為是有一定道理的:如果用戶重新加載頁面,就好像他們已經(jīng)再次瀏覽相同的 URL ,而且其他用戶都會(huì)看到他們?cè)L問的 URL,所以他們應(yīng)該重置為初始狀態(tài)。
從中我們應(yīng)該要學(xué)會(huì):
以上總結(jié)了我們對(duì)會(huì)話(Session)——— Meteor 最有用的功能之一的探索。不要忘了在進(jìn)行下一章之前,恢復(fù)你對(duì)代碼的改動(dòng)。
更多建議: