我有一些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)函数在一段时间后被调用。 我该怎么办?


当前回答

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

_.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

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

就像这样:

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:对不起,英语不是我的母语!

如果你想传递变量作为参数,让我们试试这个

如果要求是函数和var作为帕尔马,那么试试这个

setTimeout((param1,param2) => { 
     alert(param1 + param2);
     postinsql(topicId);
},2000,'msg1', 'msg2')

如果要求只是变量作为参数,那么试试这个 setTimeout((param1,param2) =>{警报(param1 + param2)},2000,' ms1 ', ' ms2 ')

你可以在ES5和ES6上尝试

用一个简单的带有两个参数的加法函数来回答这个问题。

var x = 3, y = 4;

setTimeout(function(arg1, arg2) { 
  return () => delayedSum(arg1, arg2);
}(x, y), 1000); 

function delayedSum(param1, param2) {
     alert(param1 + param2); // 7
}

我最近遇到了需要在循环中使用setTimeout的独特情况。理解这一点可以帮助您理解如何将参数传递给setTimeout。

方法1

使用forEach和Object。根据Sukima的建议:

var testObject = {
    prop1: 'test1',
    prop2: 'test2',
    prop3: 'test3'
};

Object.keys(testObject).forEach(function(propertyName, i) {
    setTimeout(function() {
        console.log(testObject[propertyName]);
    }, i * 1000);
});

我推荐这个方法。

方法2

使用绑定:

var i = 0;
for (var propertyName in testObject) {
    setTimeout(function(propertyName) {
        console.log(testObject[propertyName]);
    }.bind(this, propertyName), i++ * 1000);
}

JSFiddle: http://jsfiddle.net/MsBkW/

方法3

或者如果你不能使用forEach或bind,使用IIFE:

var i = 0;
for (var propertyName in testObject) {
    setTimeout((function(propertyName) {
        return function() {
            console.log(testObject[propertyName]);
        };
    })(propertyName), i++ * 1000);
}

方法4

但如果你不关心IE < 10,那么你可以使用Fabio的建议:

var i = 0;
for (var propertyName in testObject) {
    setTimeout(function(propertyName) {
        console.log(testObject[propertyName]);
    }, i++ * 1000, propertyName);
}

方法五(ES6)

使用块作用域变量:

let i = 0;
for (let propertyName in testObject) {
    setTimeout(() => console.log(testObject[propertyName]), i++ * 1000);
}

不过我还是推荐使用Object。在ES6中使用forEach键。