流星的范围:它似乎比局部或全球更复杂

时间:2016-03-03 23:49:46

标签: meteor scope

我在Meteor中读到的有关范围的所有内容都告诉我使用' var'变量声明前面的关键字会给出变量' file'范围而省略' var'关键字会给它'包'范围。

但是,我并不认为这是整个故事。我认为唯一的变量是真实的'文件'范围是指在任何括号外声明的范围。否则,它们的范围似乎仅限于这些括号内。

更令人困惑的是我现在面临的一个问题,即同一对象的属性具有不同的值,具体取决于它们是从括号内部还是外部访问,在这种特殊情况下是对Meteor方法的调用。

这是一些代码来说明我的意思。我将对象声明在任何括号之外,然后访问它的属性,并从内部提交其他属性的其他属性'提交表单',其中一个事件包含在' Template.inputNamesForm.events& #39 ;.首先,我填写其“inName'带有字符串值的属性,如下所示:

var name1 = {};

Template.inputNamesForm.events({
  'submit form': function (event) {

    event.preventDefault();
    name1.inName = event.target.firstName.value;

  Meteor.call('convertName', name1.inName, function (error, result) {
      name1.outName = result;
      console.log("Value as seen from inside call after button click:         name1.inName = " + name1.inName + " -- name1.outName = " + name1.outName);
    });

    console.log("Value as seen from outside call after button click: name1.inName = " + name1.inName + " -- name1.outName = " + name1.outName);
  }
)};

在为name1.inName分配字符串值之后,我使用该属性来调用对Meteor方法的调用。该方法的输出是另一个字符串,我将其分配给同一对象的不同属性,即。 name1.outName。

我的期望是,此对象的属性将包含从此文件中访问它们的任何位置的一致值。毕竟,他们应该有'' file'范围,不是吗?

但实际发生的情况却有所不同。 name1.outName的值取决于我是从Meteor方法调用的回调内部还是在其外部访问它。

如果我从回调中调用它,它具有预期值。如果我从回调外部调用它,则在第一次单击按钮后其值不确定。但是,如果再次单击该按钮,则会获取新值。它总是只需按一下按钮,即。落后,我期待它,即。从回调中调用时的值。

同样令人惊讶的是,在 Meteor方法调用之后位于之前执行之前在回调内部上方显示的console.log命令。

我必须得出结论,如果此参数在任何给定时间都有两个值,则必须有两个name1对象,一个存在于Meteor方法的回调括号中,另一个存在于其外部。但是第二个版本在哪里被调用/声明?

另一个观察结果:甚至通过省略“变量”来将变量声明为全局变量。关键字似乎无法解决括号内的项目无法被外部项目看到的问题。我真的相信Meteor中的范围比我读过的任何内容都复杂得多。我真的希望有一些全面的指南可以解释它的确切运作方式。

无论如何,我希望这是对此查询的答案:

我想知道如何让变量的值在整个代码中保持一致。更重要的是,我希望只需点击一下按钮就可以正确显示值,即。我不希望用户必须两次点击按钮才能获得正确的信息。

我很感激任何人都可以提供帮助。

与此同时,我检查了这些来源(其中包括):
https://medium.com/meteor-js/meteor-managing-the-global-namespace-5a50080a05ea#.t8gz1h3oa
http://blog.b123400.net/how-does-meteor-manage-scope/

我也看过这些主题和其他几个主题,其中大部分都让我更加困惑:
Meteor variable scope (global, client, server, or all?)
Global variables in Meteor

4 个答案:

答案 0 :(得分:1)

我不确定您问题的整个范围,所以我只关注您的代码:

var name1 = {};

Template.inputNamesForm.events({
  'submit form': function (event) {

    event.preventDefault();
    name1.inName = event.target.firstName.value;

    Meteor.call('convertName', name1.inName, function (error, result) {
      name1.outName = result;
      console.log("Value as seen from inside call after button click:         name1.inName = " + name1.inName + " -- name1.outName = " + name1.outName);
    });

    console.log("Value as seen from outside call after button click: name1.inName = " + name1.inName + " -- name1.outName = " + name1.outName);
  }
)};

我可以告诉您,当您的第一个控制台日志发生时,您将name1.outName视为未定义的原因是因为convertName方法调用是异步发生的。您可以在方法调用发生之前将name1.outName字面设置为任何内容,并且您将在第一个console.log输出中看到该值:

var name1 = {};

Template.inputNamesForm.events({
  'submit form': function (event) {

    event.preventDefault();
    name1.inName = event.target.firstName.value;
    name1.outName = "Look at me!"; // Setting name1.outName
    Meteor.call('convertName', name1.inName, function (error, result) {
      name1.outName = result;
      console.log("Value as seen from inside call after button click:         name1.inName = " + name1.inName + " -- name1.outName = " + name1.outName);
    });

    // This is going to log "Look at me!" for name1.outname the first time.
    console.log("Value as seen from outside call after button click: name1.inName = " + name1.inName + " -- name1.outName = " + name1.outName);
  }
)};

答案 1 :(得分:0)

似乎我需要以某种形式使用wrapAsync来解决此问题。我怀疑答案在于这个主题,虽然我还没有完全破译代码示例:

https://forums.meteor.com/t/how-do-fibers-and-meteor-asyncwrap-work/6087/35

坦率地说,我对Meteor使用起来有多困难感到惊讶。事实上,每当我尝试用这种语言做一些新事物时,我似乎是第一个做过这种事情的人。我提醒生活在科威特,在那里,我必须与第三世界官僚机构打交道时,多次访问各办事处才能解决问题。生活在那个国家的人必须定期完成任务。然而,办公室里似乎没有人知道如何去做。

我很抱歉抱怨,但我已经好几个月了(从2015年5月开始)并且还没有得到最简单的应用程序。说真的,怎么没有一种简单直接的方法来调用函数,从中检索信息,然后在后续命令中使用该信息?这是一件不寻常的事吗?

答案 2 :(得分:0)

好像你是在思考它。为了简单地解释它,传递给Meteor.call的回调函数将异步运行,这意味着它在完成之前不会阻止其他操作。想想纯javascript中的以下示例。

var sampleObj = {};

setTimeout(function () {
    sampleObj.testField = "I am test field.";
    console.log("Inside timeout: " + sampleObj.testField);
}, 100);

console.log("outside of timeout: " + sampleObj.testField);

请参阅JSFiddle

在这种情况下,第二个console.log也会在第一个undefined之前打印,值为setTimeout。原因是Meteor.call将在100毫秒后执行此结果,并且不会阻止其他代码的执行。 answer=$(echo $(( length / 1024 )) | bc -l) 的情况也是如此,而不是在100ms后执行代码,它等待直到从服务器获得结果。

答案 3 :(得分:0)

  

我在Meteor中读到的关于范围的一切都告诉我使用了   '无功'变量声明前面的关键字会给出   变量' file'范围而省略' var'关键字会给它   '包'范围。

使用var使其成为该文件的局部变量,省略var使其成为全局变量(如果您正在编写Meteor应用程序),如果您正在编写包本地变量。重新编写Meteor包。如果您正在编写Meteor软件包,您还可以使用软件包指定某些本地软件包变量应该是Meteor应用程序的全局变量(您可以在package.js文件中指定)。

  但是,我并不认为这是整个故事。我认为这是唯一的   时间变量有真实的文件'范围是它们被声明的时间   在任何括号之外。否则,它们的范围似乎仅限于   在这些括号内。

不,这里没有任何魔法。使用普通的JavaScript,但每个JavaScript文件都将包含(function(){ <your-code-here> })()。这就是创建&#34;文件范围&#34; (函数是在ES2015之前在JavaScript中创建范围的唯一方法)。

您的观察行为是预期的。如果你发现这很奇怪,你可能还没有理解同步和异步之间的区别。 JavaScript是单线程的,因此如果所有内容都是同步的,那么所有定时器和通过JavaScript完成的与服务器的通信都会冻结/暂停您的JavaScript代码。为避免这种情况,我们强制使用异步调用。对于使用JavaScript的所有框架都是如此,并且不仅限于Meteor应用程序。

回调是一种功能,当结果准备就绪时将在未来某个时间被调用(例如,当我们向服务器发送请求后我们已从服务器返回结果时)。这就是为什么您的外console.log在内部console.log之前执行的原因。

使用大量回调会使您的代码难以阅读。在Node JS中,他们添加了future包,您可以使用它来使用异步函数,就好像它们是同步的一样。但是,此功能无法在纯JavaScript中实现,因此您无法在客户端使用它,您的所有代码都必须是JavaScript代码。这真的很难过,但在Meteor中有一个很好的解决方案:反应变量!

我不知道我是否帮助过这个答案,但随时可以提出跟进问题。