2014-12-02 57 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