Meteor中使用Session变量的偶发行为

时间:2012-06-02 00:54:01

标签: meteor

我一直在摸索为什么这段代码会在某些时候起作用,但不是全部(或者至少在大多数情况下)。我发现它实际上确实在某些时候在浏览器中显示正确的内容,但奇怪的是,有几天我会回到相同的代码,运行服务器(按照正常情况)并在加载时页面将在控制台中收到错误:TypeError: 'undefined' is not an object (evaluating 'Session.get('x').html')

(当我收到该错误时,控制台中的下一行有时会显示Error - 引用err对象,有时会读取Object - 引用data对象!?)。

我显然在Meteor中遗漏了一些关于会话变量的内容并且必须滥用它们?我希望有经验的人能指出我正确的方向。

先谢谢你的帮助!

这是我的虚拟代码:

/client/del.html
<head>
  <title>del</title>
</head>

<body>
  {{> hello}}
</body>

<template name="hello">
  Hello World!
  <div class="helloButton">{{{greeting}}}</div>
</template>

我的客户端javascript文件是:

/client/del.js
Meteor.call('foo', 300, function(err, data) {
  err ? console.log(err) : console.log(data);
  Session.set('x', data);
});

Template.hello.events = {
  'click div.helloButton' : function(evt) {
    if ( Session.get('x').answer.toString() === evt.target.innerHTML ) {
      console.log('yay!');
    }
  } 
};

Template.hello.greeting = function() {
  return Session.get('x').html;
};

我的服务器端javascript是:

/server/svr.js
Meteor.methods({

  doubled: function(num) {
    return num * 2;
  },

  foo: function(lmt) {
    var count = lmt,
        result = {};

    for ( var i = 0; i < lmt; i++ ) {
        count++;
    }

    count = Meteor.call('doubled', count);

    result.html = "<em>" + count + "</em>";
    result.answer = count;
    return result;

  }

});

2 个答案:

答案 0 :(得分:1)

我认为,当客户端首次启动时,会话变量还没有设置好。因此,Session.get('x')将返回undefined,直到您的方法调用(foo)返回,这几乎肯定不会在模板首次绘制之前发生。

然而,之后它会在会话中,所以一旦刷新,事情可能会正常。

答案是在尝试访问变量之前检查它是否为undefined。例如:

Template.hello.greeting = function() {
  if (Session.get('x')) return Session.get('x').html;
};

答案 1 :(得分:1)

Meteor的seven principles之一是:

  

延迟补偿。在客户端上,使用预取和模型模拟使其看起来像是与数据库的零延迟连接。

由于存在延迟,您的客户端将首先尝试根据客户端连接时的数据绘制布局。然后它将进行呼叫,然后它将根据呼叫进行更新。有时呼叫可能能够快速响应以便同时绘制。

现在有可能没有设置变量,它会在那种情况下抛出异常,从而中断执行(因为调用堆栈中的函数不会继续运行)。

有两种可能的解决方案:

  1. 使用时检查变量是否已设置。

    return Session.get('x') ? Session.get('x').html : '';

  2. 通过将变量设置在脚本顶部,确保变量具有初始值。

    Session.set('x', { html = '', answer = ''});

  3. 另一种方法是在呼叫响应后添加模板。

    Meteor.call('foo', 300, function(err, data) {
        Session.set('x', data);
        $('#page').html(Meteor.ui.render(function() {
            return Template.someName();
        }));
    });