我在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
答案 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中有一个很好的解决方案:反应变量!
我不知道我是否帮助过这个答案,但随时可以提出跟进问题。