2014-12-02 55 views
2

我正試圖圍繞流星的反應性包裹我的頭。我知道,當模板中引用的被動數據源發生更改時,它會重新呈現頁面。我也明白什麼構成被動源(Session,MongoDB遊標等)。瞭解流星何時重新計算我的模板幫手

我無法理解的是所有這些「背後」打電話給我的模板助手。似乎有超過反應性導致他們。

特別是,在下面的代碼,我有一個friendRequests幫手獲取訪問/friends頁面時有時重新計算有時倍。如果它重新計算兩次,數據庫查詢成功!如果重新計算了三次,則第一個數據庫訪問(出於某種奇怪的原因)無法查詢數據庫,而後者則成功。

這是堆棧跟蹤時,DB失敗:

// NOTE: imsolonely is one of the users that should be returned in the friendRequests 
imsolonely's public key: undefined 
debug.js:41 Exception in template helper: TypeError: Cannot read property 'profile' of undefined 
    at Object.Utils.getPublicKeyByUsername (http://localhost:3000/lib/utils.js?acf4e03d4c8a70819c26f8d2fd08caf7100768fe:79:22) 
    at Object.Utils.getFingerprintByUsername (http://localhost:3000/lib/utils.js?acf4e03d4c8a70819c26f8d2fd08caf7100768fe:88:24) 
    at http://localhost:3000/client/friends.js?dbec4a7537c9d0abf56a74489824969cb7baadfe:25:35 
    at Array.forEach (native) 
    at Function._.each._.forEach (http://localhost:3000/packages/underscore.js?0a80a8623e1b40b5df5a05582f288ddd586eaa18:156:11) 
    at Object.Template.friendRequests.helpers.friendRequests (http://localhost:3000/client/friends.js?dbec4a7537c9d0abf56a74489824969cb7baadfe:22:7) 
    at http://localhost:3000/packages/blaze.js?77c0809654ee3a10dcd5a4f961fb1437e7957d33:2693:16 
    at http://localhost:3000/packages/blaze.js?77c0809654ee3a10dcd5a4f961fb1437e7957d33:1602:16 
    at Object.Spacebars.dot (http://localhost:3000/packages/spacebars.js?3c496d2950151d744a8574297b46d2763a123bdf:231:13) 
    at http://localhost:3000/client/template.friends.js?a2da726f6dad1aaecfdedfe216aa3378fff938b5:24:37 
utils.js?acf4e03d4c8a70819c26f8d2fd08caf7100768fe:78 imsolonely's public key: {"profile":{"publicKey":"0404b4880129edc1ea2652dd1eff1c8728269874b9b0ace02cc90edcb449c3f3d716c2f8b79a5fe5695d52cd85aed228f977073538625e8e71f1cfd764766669b1"},"_id":"sXjzt7YHA8KTyAib5"} 
utils.js?acf4e03d4c8a70819c26f8d2fd08caf7100768fe:78 imsolonely's public key: {"profile":{"publicKey":"0404b4880129edc1ea2652dd1eff1c8728269874b9b0ace02cc90edcb449c3f3d716c2f8b79a5fe5695d52cd85aed228f977073538625e8e71f1cfd764766669b1"},"_id":"sXjzt7YHA8KTyAib5"} 

這也與許多發生(或全部,不知道)我的助手。當它們不應該被需要時,它們會被調用,因爲用戶沒有登錄(並且模板不被渲染,因此不應該重新計算幫助器)。

下面是一些代碼:

client/friends.js

Template.friendRequests.helpers({ 
    friendRequests: function() { 
    // Problem 1: The template gets called right after I log in but before I am fully logged in 
    // so I need this call here. 
    if(!Meteor.user()) 
     return Utils.notLoggedInErrorMsg; 

    // Problem 2: The template gets called three times. The first time fails the DB query 
    // as if the DB row did not exist. The next 2 times it succeeds. But it should only be 
    // called once. 
    var reqs = Friends.getFriendRequests(Utils.me()); 

    _.each(reqs, function(element, it, list) { 
     check(element.initiator, String); 
     // Get the user's fingerprint 
     element.fingerprint = Utils.getFingerprintByUsername(element.initiator); 
    }); 

    return reqs; 
    }, 
}); 

client/friends.html

<template name="friends"> 
    {{> friendRequests}} 
    {{> searchForm}} 

    <h2>My friends</h2> 
    <ul> 
    {{#each friends}} 
    <li>{{this}}</li> 
    {{/each}} 
    </ul> 
</template> 

<template name="friendRequests"> 
    <h2>Friend requests</h2> 
    {{#if friendRequests.length}} 
    <p>Someone's popular today!</p> 
    <ul> 
    {{#each friendRequests}} 
     <li><b>{{initiator}}</b> with fingerprint <pre style="display: inline">{{fingerprint}}</pre> sent you a request on <em>{{date}}</em>. <a href="#">Accept <b>{{initiator}}</b> as a friend?</a></li> 
    {{/each}} 
    </ul> 
    {{else}} 
    <p>Sorry, nobody likes you right now.</p> 
    {{/if}} 
</template> 

lib/utils.js

Utils = { 
    // ... 
    // other stuff 
    // ... 

    // @return a hex-encoded public key as a string 
    getPublicKeyByUsername: function (username) { 
    var user = Meteor.users.findOne({ username: username }, { fields: { 'profile.publicKey': 1 } }); 
    console.log(username + '\'s public key: ' + EJSON.stringify(user)); 
    var pubKey = user.profile.publicKey; 

    return pubKey; 
    }, 

    // NOTE: not used yet, i used the CryptoUtils function directly when I needed it 
    // 
    // @return the fingerprint as a hex-encoded string 
    getFingerprintByUsername: function (username) { 
    var pubKey = Utils.getPublicKeyByUsername(username); 

    var fingerprint = CryptoUtils.getPublicKeyFingerprint(pubKey); 

    return fingerprint; 
    }, 

    notLoggedInErrorMsg: 'Meteor is being silly and calling this when I\'m not logged in.', 
} 

如果重要,我使用iron:router 1.0.3包重定向到/friends URL。

任何澄清爲什麼friendRequests助手正在重新計算,爲什麼它有時重新計算兩次,有時三次,而不是一次當我刷新/friends頁將不勝感激!

謝謝 阿林

回答

4

一般來說,你應該想到的是你的助手將調用多次。如果您的模板被呈現在用戶登錄,並且無需等待上公佈的數據,很可能是你的助手將運行:

  1. 當請求
  2. 路線當用戶完成登錄在
  3. Friends數據首先到達客戶端
  4. 當附加Friends數據到達或修改

爲了解決第一個問題,您可以檢查f。關於或Meteor.user() || Meteor.loggingIn(),正如我在回答this question時所做的那樣(請注意路由器API已經改變,因爲我回答了這個問題,但它應該讓你知道該怎麼做)。

您的第二個問題的答案可以在我的帖子中找到guards。簡而言之,您不能假定數據已到達客戶端,因此您需要檢查其是否存在,或者您需要在呈現模板之前明確指定您的路由器中的訂閱。

+0

因此,我確實有一個'Router.configure()',它設置了默認佈局,並且在所有**代碼所需的所有'Meteor.subscribe'調用中都有一個'waitOn'。我還有一個'Router.onBeforeAction',它可以重定向到一個*版本不同的登錄頁面。當Meteor.user()== false時,我甚至不喜歡在'Meteor.user()'模板中檢查數十個模板,當這些模板甚至不被渲染時(或者至少不應該渲染) '。 – 2014-12-02 20:27:22

+0

另外,即使我到處檢查,我會返回什麼?我猜測null是一個壞主意。那麼,我是否會爲每個模板助手構造並返回該助手類型的虛擬對象?沒有更好的方法來做到這一點? – 2014-12-02 20:27:41

+0

此外,守衛的東西可能是可接受的簡單代碼,如'var post = Posts.findOne(); return posts && posts.id;'但是,它使複雜的簡單/線性代碼在返回之前需要稍微處理DB數據。編程開銷將被添加到您編寫的每個幫助程序以及您在該幫助程序中查詢的每個集合。我希望有一個Meteor特有的方法來確保在某些幫助程序中你有:** 1。** Meteor.user()'始終是登錄用戶的ID。 ** 2。**當數據在那裏並且查詢正確時,數據庫查詢不應該因爲不好的原因而失敗。 – 2014-12-02 20:35:27

2

事實證明我的waitOn掛鉤出現錯誤。我沒有返回任何東西,我只是撥打Meteor.subscribe()而不是返回它們的數組。下面是固定的DB例外:

Router.configure({ 
    layoutTemplate: 'mainLayout', 
    loadingTemplate: 'loading', 
    waitOn: function() { 
    return [ 
     Meteor.subscribe('userData'), 
     Meteor.subscribe('allUserData'), 
     Meteor.subscribe('UserProfiles'), 
    ]; 
    }, 
}); 

我還沒有爲Meteor.user()是不確定的一個很好的解決方案。或者,這也解決了它?

PS:謝謝@DavidWeldon幫助我縮小範圍!

+0

是的,我犯了同樣的錯誤。我很高興你明白了。 :) – 2014-12-02 21:10:10