我有一些JavaScript代码,看起来像:

function statechangedPostQuestion()
{
  //alert("statechangedPostQuestion");
  if (xmlhttp.readyState==4)
  {
    var topicId = xmlhttp.responseText;
    setTimeout("postinsql(topicId)",4000);
  }
}

function postinsql(topicId)
{
  //alert(topicId);
}

我得到一个错误,topicId没有定义 在我使用setTimeout()函数之前,一切都在工作。

我希望我的postinsql(topicId)函数在一段时间后被调用。 我该怎么办?


当前回答

我是如何解决这个问题的?

就像这样:

setTimeout((function(_deepFunction ,_deepData){
    var _deepResultFunction = function _deepResultFunction(){
          _deepFunction(_deepData);
    };
    return _deepResultFunction;
})(fromOuterFunction, fromOuterData ) , 1000  );

setTimeout等待一个函数的引用,所以我在一个闭包中创建了它,它解释了我的数据,并返回一个具有我的数据的良好实例的函数!

也许你可以改进这部分:

_deepFunction(_deepData);

// change to something like :
_deepFunction.apply(contextFromParams , args); 

我在chrome, firefox和IE上测试了它,它执行得很好,我不知道性能如何,但我需要它工作。

一个示例测试:

myDelay_function = function(fn , params , ctxt , _time){
setTimeout((function(_deepFunction ,_deepData, _deepCtxt){
            var _deepResultFunction = function _deepResultFunction(){
                //_deepFunction(_deepData);
                _deepFunction.call(  _deepCtxt , _deepData);
            };
        return _deepResultFunction;
    })(fn , params , ctxt)
, _time) 
};

// the function to be used :
myFunc = function(param){ console.log(param + this.name) }
// note that we call this.name

// a context object :
myObjet = {
    id : "myId" , 
    name : "myName"
}

// setting a parmeter
myParamter = "I am the outer parameter : ";

//and now let's make the call :
myDelay_function(myFunc , myParamter  , myObjet , 1000)

// this will produce this result on the console line :
// I am the outer parameter : myName

也许你可以改变签名,使其更符合要求:

myNass_setTimeOut = function (fn , _time , params , ctxt ){
return setTimeout((function(_deepFunction ,_deepData, _deepCtxt){
            var _deepResultFunction = function _deepResultFunction(){
                //_deepFunction(_deepData);
                _deepFunction.apply(  _deepCtxt , _deepData);
            };
        return _deepResultFunction;
    })(fn , params , ctxt)
, _time) 
};

// and try again :
for(var i=0; i<10; i++){
   myNass_setTimeOut(console.log ,1000 , [i] , console)
}

最后来回答最初的问题:

 myNass_setTimeOut( postinsql, 4000, topicId );

希望对大家有所帮助!

Ps:对不起,英语不是我的母语!

其他回答

这是一个已经有“正确”答案的老问题,但我想我要提到另一种没有人在这里提到过的方法。这是从优秀的下划线库复制和粘贴:

_.delay = function(func, wait) {
  var args = slice.call(arguments, 2);
  return setTimeout(function(){ return func.apply(null, args); }, wait);
};

你可以传递尽可能多的参数给setTimeout调用的函数,作为一个额外的奖励(好吧,通常是一个奖励),传递给你的函数的参数的值在你调用setTimeout时被冻结,所以如果它们在setTimeout()被调用和超时之间的某个点上改变了值,嗯…这已经不再令人沮丧了:)

这里有一把小提琴,你可以明白我的意思。

请注意,topicId在错误消息中“未定义”的原因是在执行setTimeout时它作为一个局部变量存在,而在延迟调用postinsql时不存在。变量生存期尤其重要,特别是在尝试将“this”作为对象引用传递时。

我听说您可以将topicId作为第三个参数传递给setTimeout函数。没有给出太多细节,但我得到了足够的信息来让它工作,它在Safari中是成功的。我不知道他们所说的“毫秒误差”是什么意思。看看这里:

http://www.howtocreate.co.uk/tutorials/javascript/timers

我知道它很老了,但我想加入我喜欢的味道。

我认为实现这一点的一种相当易读的方法是将topicId传递给一个函数,该函数反过来使用参数在内部引用主题ID。即使外部的topicId不久后将被更改,该值也不会改变。

var topicId = xmlhttp.responseText;
var fDelayed = function(tid) {
  return function() {
    postinsql(tid);
  };
}
setTimeout(fDelayed(topicId),4000);

或短:

var topicId = xmlhttp.responseText;
setTimeout(function(tid) {
  return function() { postinsql(tid); };
}(topicId), 4000);
setTimeout(function() {
    postinsql(topicId);
}, 4000)

您需要将匿名函数作为参数而不是字符串提供,根据ECMAScript规范,后一种方法甚至不应该工作,但浏览器只是宽容。这是正确的解决方案,当使用setTimeout()或setInterval()时,不要依赖于传递字符串作为“函数”,它更慢,因为它必须被计算,这是不正确的。

更新:

正如Hobblin在他对问题的评论中所说,现在你可以使用function .prototype.bind()将参数传递给setTimeout内的函数。

例子:

setTimeout(postinsql.bind(null, topicId), 4000);

在做了一些研究和测试之后,唯一正确的实现是:

setTimeout(yourFunctionReference, 4000, param1, param2, paramN);

setTimeout将所有额外的参数传递给你的函数,以便在那里处理它们。

匿名函数可以用于非常基本的东西,但在一个对象的实例中,你必须使用“this”,没有办法使它工作。 任何匿名函数都会将“this”更改为指向窗口,因此您将失去对象引用。