我已经编程了几年,但我是JavaScript的新手。我正在尝试创建一个标准线程'notify'函数的hacky版本。我正在运行一系列ajax数据请求,每个请求执行大约需要200毫秒,我需要等待它们完成才能执行操作(绘制图形)。
我的解决方案是让每个线程在完成后增加一个全局变量。然后,我使用setTimeout创建了一个计时器,每100毫秒检查一次,看看是否所有线程都更新了变量,如果有,则执行操作。
尽管有点hacky,但这很有用。
快进几周到未来,我的计划正在发展,我们现在需要做到 能够在同一页面上有多个图表,每个图表使用上述ajax请求独立管理其数据,以及使用图表的几个不同页面。因此,我将图形代码提取到带有require.js的模块中,并定义一个执行图形化的类,以将每个图形与其他图形隔离,但突然setInterval不起作用。我做一些谷歌搜索并找到以下文章,我有点理解......
所以无论如何,当使用setInterval时,似乎'this'成为某个奇怪原因的窗口,因此它无法看到我的方法。
无论如何,我尝试创建一个var inst来显式地包含'this',这似乎有所帮助,但由于某种原因它不喜欢在递归调用中将'inst'作为参数传递。来自Firebug控制台的错误消息是:
元素列表后缺少] [打破此错误]
}(9.9,[object Object]))
以下是我的代码中的示例:
var inst = this;
// some code... then in a function...
function (){
inst.waitUntil(10, inst);
}
inst.waitUntil = function(how_many_seconds, inst){
if (how_many_seconds < 0){
alert("Script timed out.");
return;
} else {
if (inst.allSchoolsLoaded()){
setTimeout("("+inst.draw+"("+inst.after+"))", 100);
} else {
var argString = "("+inst.waitUntil+"("+(how_many_seconds-0.1)+", "+inst+"))";
//alert(argString);
setTimeout(argString, 100);
}
}
}
您可以假设所有提到的变量都是在类的前面定义的。
我在这里结识,任何帮助都会非常感激。如果任何人都可以为完全避免setInterval的线程问题提出更好的解决方案,那就太棒了,否则如果你可以提出一种让setInterval工作的方法,或者另外一个很好的替代函数。
jQuery是可用的,我不介意安装其他工具,如果他们会帮助。
非常感谢,
亚历
答案 0 :(得分:3)
您正在尝试使用对象创建字符串。对象的标准字符串表示形式为[object Object]
。您可能也会遇到inst.waitUntil
的问题,因为它被转换为函数的字符串表示形式(这是某些(大多数?)浏览器中函数的来源)。
只需将函数传递给setTimeout
:
setTimeout(function() {
inst.waitUntil(how_many_seconds-0.1, inst);
}, 100);
现在,在waitUntil
内,this
将引用inst
。鉴于此,您可以进一步简化代码。
例如:
this.waitUntil = function(how_many_seconds){
var self = this;
if (how_many_seconds < 0){
alert("Script timed out.");
return;
} else {
var callback = function() {
self.waitUntil(how_many_seconds-0.1);
};
if (this.allSchoolsLoaded()){
callback = function() {
self.draw(self.after);
};
}
setTimeout(callback, 100);
}
};
答案 1 :(得分:1)
不要使用字符串,它在内部使用eval
,这对代码的性能和可维护性都有害。而不是:
if (inst.allSchoolsLoaded()){
setTimeout("("+inst.draw+"("+inst.after+"))", 100);
} else {
var argString = "("+inst.waitUntil+"("+(how_many_seconds-0.1)+", "+inst+"))";
//alert(argString);
setTimeout(argString, 100);
}
这样做:
if (inst.allSchoolsLoaded()){
setTimeout(function () {
inst.draw(inst.after);
}, 100);
} else {
setTimeout(function () {
inst.waitUntil(how_many_seconds - 0.1);
}, 100);
}
此外,如果您在实例上使用inst
方法,则无需传递waitUntil
,this
上下文将自设为inst
,因此:< / p>
inst.waitUntil = function (seconds) {
// `this` is now pointing at `inst`
// we will cache a reference to the object into a variable
// because anonymous function will have its own context (`this`)
// in the link provided in comment you can see alternatives such as using
// ECMAScript `bind` Function method to bind function context to certain object
var self = this;
if ( seconds < 0 ) return alert('timeout');
if ( inst.allSchoolsLoaded() ){
setTimeout(function () {
self.draw(self.after);
}, 100);
} else {
setTimeout(function () {
self.waitUntil(seconds - 0.1);
}, 100);
}
};
答案 2 :(得分:0)
此处发布的解决方案完美无缺,感谢您的帮助。
如果其他人有类似的需要执行多个AJAX请求,我实际上偶然发现了一个优雅处理它的jQuery方法:
http://api.jquery.com/jQuery.when/
它可能需要几个'Deferred'对象,包括ajax请求,并等待所有这些对象成功执行或其中一个失败。使用它,我可以完全摆脱我的setInterval计时器。
干杯,
亚历