javascript - 将对象参数传递给setInterval

时间:2012-02-24 01:20:11

标签: javascript jquery ajax

我已经编程了几年,但我是JavaScript的新手。我正在尝试创建一个标准线程'notify'函数的hacky版本。我正在运行一系列ajax数据请求,每个请求执行大约需要200毫秒,我需要等待它们完成才能执行操作(绘制图形)。

我的解决方案是让每个线程在完成后增加一个全局变量。然后,我使用setTimeout创建了一个计时器,每100毫秒检查一次,看看是否所有线程都更新了变量,如果有,则执行操作。

尽管有点hacky,但这很有用。

快进几周到未来,我的计划正在发展,我们现在需要做到 能够在同一页面上有多个图表,每个图表使用上述ajax请求独立管理其数据,以及使用图表的几个不同页面。因此,我将图形代码提取到带有require.js的模块中,并定义一个执行图形化的类,以将每个图形与其他图形隔离,但突然setInterval不起作用。我做一些谷歌搜索并找到以下文章,我有点理解......

http://www.novogeek.com/post/2010/02/08/Scope-problems-with-JavaScript-setInterval-setTimeout-Use-closures!.aspx

所以无论如何,当使用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是可用的,我不介意安装其他工具,如果他们会帮助。

非常感谢,

亚历

3 个答案:

答案 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方法,则无需传递waitUntilthis上下文将自设为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计时器。

干杯,

亚历