<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                --- title: 延遲補償 slug: latency-compensation date: 0007/01/02 number: 7.5 points: 5 sidebar: true photoUrl: http://www.flickr.com/photos/ikewinski/9473352049/ photoAuthor: Mike Lewinski contents: 理解延遲補償(Latency Compensation)。|減慢你的 App 看看發生了什么。|學習 Meteor 的內置方法如何互相調用。 paragraphs: 28 --- 在上一章,我們介紹了 Meteor 的一個新概念:**內置方法**。 <%= diagram "latency1", "沒有延遲補償的情況", "pull-right" %> Meteor 的內置方法是一種在服務器上執行一系列命令的結構化方法。在示例中,我們使用內置方法是為了確保新帖子是通過作者的姓名和 ID ,以及當前服務器時間去標記。 然而,如果 Meteor 用最基本的方式去執行內置方法,我們會注意到一些問題。想一想下面事件的序列(注:為演示方便,時間戳值是隨機的生成的): - *+0ms:* 用戶單擊提交按鈕,瀏覽器觸發內置方法的調用。 - *+200ms:* 服務器更改 Mongo 數據庫。 - *+500ms:* 客戶端接收到這些變化,并更新頁面反映更改結果。 如果這是 Meteor 的操作方式,它會有一個很短的時間差去看到這樣的執行操作的結果(延時的多少會取決于你的服務器性能)。但我們不可能讓這些情況出現在 Web 應用程序中! ### 延遲補償 <%= diagram "latency2", "延遲補償的情況", "pull-right" %> 為了避免這個問題,Meteor 引入了一個叫做**延遲補償(Latency Compensation)**的概念。如果我們把 `post` 方法的定義放在 `collections/` 目錄下。這意味著它在服務端和客戶端上都存在,而且是同時運行! 當你使用內置方法的時候,客戶端會發送請求到服務器去調用,同時還模仿服務器內置方法去操作本地數據庫集合。所以現在我們的工作流程是: - *+0ms:* 用戶單擊提交按鈕,瀏覽器觸發內置方法的調用。 - *+0ms:* 客戶端模仿內置方法操作本地的數據集合和以及通過更改頁面來反映這一變化。 - *+200ms:* 服務器更改 Mongo 數據庫。 - *+500ms:* 客戶端接收這些更改并取消剛剛的模仿操作,根據服務器的更改覆蓋它們(通常是相同的)。頁面的變化反映了這一過程。 這樣用戶就會立刻看到變化。服務器的響應返回一段時間后,根據服務器數據庫發送過來的更改請求,本地數據庫可能會或可能不會有明顯的改變。因此,我們應該學會確保本地數據盡可能地與服務器數據庫保持一致。 ### 觀察延遲補償 我們可以對 `post` 內置方法的調用稍作改動。為此,我們將會通過 npm 包 `futures` ,使用一些高級的編程方式去把延遲對象放到我們的內置方法調用里面。 我們將使用 `isServer` 去問 Meteor 現在所調用的內置方法是在客戶端被調用(作為一個存根 Stub)或是在服務器端。這個存根 [stub](http://docs.meteor.com/#methods_header) 是模仿內置方法在客戶端運行的模擬方法,而“真正的”內置方法是在服務器上運行的。 所以我們會詢問 Meteor 這部分代碼是否在服務器端執行。如果是,我們會在帖子的標題后面添加 `(server)` 字符串。如果不是,我們將添加 `(client)` 字符串: ~~~js Posts = new Mongo.Collection('posts'); Meteor.methods({ postInsert: function(postAttributes) { check(this.userId, String); check(postAttributes, { title: String, url: String }); if (Meteor.isServer) { postAttributes.title += "(server)"; // wait for 5 seconds Meteor._sleepForMs(5000); } else { postAttributes.title += "(client)"; } var postWithSameLink = Posts.findOne({url: postAttributes.url}); if (postWithSameLink) { return { postExists: true, _id: postWithSameLink._id } } var user = Meteor.user(); var post = _.extend(postAttributes, { userId: user._id, author: user.username, submitted: new Date() }); var postId = Posts.insert(post); return { _id: postId }; } }); ~~~ <%= caption "collections/posts.js" %> <%= highlight "11~17" %> 如果我們到此為止,這個演示就不那么有意義。當前,看起來就像是帖子表單提交后暫停了5秒鐘,然后轉到主帖子列表,沒發生其他事情。 為了理解這是為什么,讓我們看看帖子提交的事件 handler: ~~~js Template.postSubmit.events({ 'submit form': function(e) { e.preventDefault(); var post = { url: $(e.target).find('[name=url]').val(), title: $(e.target).find('[name=title]').val() }; Meteor.call('postInsert', post, function(error, result) { // display the error to the user and abort if (error) return alert(error.reason); // show this result but route anyway if (result.postExists) alert('This link has already been posted'); Router.go('postPage', {_id: result._id}); }); } }); ~~~ <%= caption "client/templates/posts/post_submit.js" %> 我們在方法 call 回調函數中放了 `Router.go()` 路由函數。 現在的行為通常是正確的。畢竟,你不能在確定他們帖子提交是否有效之前去跳轉用戶,只是因為如果立即跳轉走,然后幾秒鐘后再轉回到原始帖子頁面去更正數據,這會非常令人困惑。 但是對于這個例子而言,我們想立即看看結果。所以我們將路由更改到 `postsList` 路由(我們還不能路由到帖子,因為在方法之外我們不知道帖子的 `_id`),把它從回調函數中移出來,看看會發生什么: ~~~js Template.postSubmit.events({ 'submit form': function(e) { e.preventDefault(); var post = { url: $(e.target).find('[name=url]').val(), title: $(e.target).find('[name=title]').val() }; Meteor.call('postInsert', post, function(error, result) { // display the error to the user and abort if (error) return alert(error.reason); // show this result but route anyway if (result.postExists) alert('This link has already been posted'); }); Router.go('postsList'); } }); ~~~ <%= caption "client/templates/posts/post_submit.js" %> <%= highlight "20" %> <%= scommit "7-5-1", "Demonstrate the order that posts appear using a sleep." %> 如果我們現在創建一個帖子,我們可以清楚地看到延遲補償。首先,插入一個標題帶 `(client)` 的帖子(列表的第一個帖子,鏈接到 GitHub): <%= screenshot "s5-1", "我們的帖子首先儲存在客戶端集合" %> 接著,五秒之后,它就會被服務器插入的真正帖子文檔所替代: <%= screenshot "s5-2", "我們的帖子在客戶端收到來自服務器端集合傳來的更新" %> ### 客戶端集合內置方法 通過上面所說的,你可能會認為內置方法很復雜,但事實上它們也可以相當簡單。實際上我們已經用過三個非常簡單的內置方法:集合的操作方法 `insert`、`update` 和 `remove`。 當你定義一個服務器集合稱為 `'posts'` ,你已經隱式地定義了這三個內置方法: `posts/insert`、`posts/update` 和 `posts/delete`。換句話說,當你在本地集合中調用 `Posts.insert()`,你已經在調用延時補償方法來做下面這兩件事: 1. 檢查我們是否允許通過調用 `allow` 和 `deny` 方法的回調去操作集合(然而這并不需要發生在內置方法的模擬)。 2. 實際地修改底層的數據庫。 ### 內置方法的相互調用 你可能已經意識到當我們插入帖子的時候,`post` 的內置方法調用了另一個內置方法(`posts/insert`)。這是如何工作的呢? 當模擬方法(客戶端版本的內置方法)開始運行,模擬方法執行 `insert`(插入的是本地集合)時,我們不叫它真正的服務器端 `insert`,但我們會認為*服務器端*的 `post` 也將會同樣的被插入。 因此,當服務器端的 `post` 調用內置方法 `insert` 的時候更加沒有必要去擔心的客戶端模擬方法,它肯定能夠在客戶端順利地插入。 像之前一樣,在閱讀下一章之前,不要忘記還原你所做的更改。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看