948

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

4

29 回答 29

1243
setTimeout(function() {
    postinsql(topicId);
}, 4000)

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

更新:

正如霍布​​林在对问题的评论中所说,现在您可以使用 setTimeout 将参数传递给函数Function.prototype.bind()

例子:

setTimeout(postinsql.bind(null, topicId), 4000);
于 2009-07-27T21:15:26.263 回答
842

在现代浏览器(即 IE11 及更高版本)中,“setTimeout”接收第三个参数,该参数在计时器结束时作为参数发送给内部函数。

例子:

var hello = "Hello World";
setTimeout(alert, 1000, hello);

更多细节:

于 2011-09-21T17:23:04.260 回答
181

经过一些研究和测试,唯一正确的实现是:

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

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

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

于 2012-10-30T22:08:46.347 回答
47

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

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

您可以将任意数量的参数传递给 setTimeout 调用的函数作为额外的奖励(通常是奖励),当您调用 setTimeout 时,传递给函数的参数的值会被冻结,所以如果它们改变值在调用 setTimeout() 和超时之间的某个时间点,嗯......这不再那么令人沮丧了:)

这是一个小提琴,您可以在其中看到我的意思。

于 2012-12-18T14:28:54.343 回答
41

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

方法一

根据 Sukima 的建议,使用forEachand :Object.keys

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

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

我推荐这种方法。

方法二

使用bind

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/

方法三

或者,如果您不能使用forEachor bind,请使用IIFE

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

方法四

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

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

方法 5 (ES6)

使用块范围的变量:

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

虽然我仍然建议在 ES6 中使用Object.keyswith 。forEach

于 2013-07-09T19:58:32.167 回答
27

霍布林已经对这个问题发表了评论,但它真的应该是一个答案!

UsingFunction.prototype.bind()是最干净、最灵活的方法(另外还可以设置this上下文):

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

有关更多信息,请参阅这些 MDN 链接:
https ://developer.mozilla.org/en/docs/DOM/window.setTimeout#highlighter_547041 https://developer.mozilla.org/en/docs/JavaScript/Reference/Global_Objects/Function /bind#With_setTimeout

于 2013-03-25T16:34:04.130 回答
17

有些答案是正确的,但令人费解。

4 年后我再次回答这个问题,因为我仍然遇到过于复杂的代码来准确解决这个问题。有一个优雅的解决方案。

首先,在调用 setTimeout 时不要传入字符串作为第一个参数,因为它有效地调用了对慢速“eval”函数的调用。

那么我们如何将参数传递给超时函数呢?通过使用闭包:

settopic=function(topicid){
  setTimeout(function(){
    //thanks to closure, topicid is visible here
    postinsql(topicid);
  },4000);
}

...
if (xhr.readyState==4){
  settopic(xhr.responseText);
}

有人建议在调用超时函数时使用匿名函数:

if (xhr.readyState==4){
  setTimeout(function(){
    settopic(xhr.responseText);
  },4000);
}

语法有效。但是到调用 settopic 时,即 4 秒后,XHR 对象可能不一样了。因此,预先绑定变量很重要。

于 2014-01-19T06:00:29.197 回答
17

您可以将参数传递给 setTimeout 回调函数,如下所示:

setTimeout(函数, 毫秒, param1, param2, ...)

例如。

function myFunction() {
  setTimeout(alertMsg, 3000, "Hello");
}

function alertMsg(message) {
    alert(message)
}
于 2019-05-28T13:36:58.887 回答
15

我知道这个问题被问到已经 10 年了,但是,如果你已经滚动到这里,我认为你仍然面临一些问题。Meder Omuraliev 的解决方案是最简单的解决方案,可能对我们大多数人有所帮助,但对于那些不想有任何约束力的人来说,这里是:

  1. 使用参数设置超时
setTimeout(function(p){
//p == param1
},3000,param1);
  1. 使用立即调用函数表达式 (IIFE)
let param1 = 'demon';
setTimeout(function(p){
    // p == 'demon'
},2000,(function(){
    return param1;
})()
);
  1. 问题的解决方案
function statechangedPostQuestion()
{
  //alert("statechangedPostQuestion");
  if (xmlhttp.readyState==4)
  {
    setTimeout(postinsql,4000,(function(){
        return xmlhttp.responseText;
    })());
  }
}

function postinsql(topicId)
{
  //alert(topicId);
}
于 2019-12-02T17:52:05.350 回答
12

代替

 setTimeout("postinsql(topicId)", 4000);

 setTimeout("postinsql(" + topicId + ")", 4000);

或者更好的是,用匿名函数替换字符串表达式

 setTimeout(function () { postinsql(topicId); }, 4000);

编辑:

Brownstone 的评论不正确,这将按预期工作,如在 Firebug 控制台中运行所示

(function() {
  function postinsql(id) {
    console.log(id);
  }
  var topicId = 3
  window.setTimeout("postinsql(" + topicId + ")",4000); // outputs 3 after 4 seconds
})();

请注意,我同意其他人的观点,即您应该避免将字符串传递给,setTimeout因为这将调用eval()字符串,而是传递一个函数。

于 2009-07-27T21:16:10.117 回答
12

我的答案:

setTimeout((function(topicId) {
  return function() {
    postinsql(topicId);
  };
})(topicId), 4000);

解释:

创建的匿名函数返回另一个匿名函数。这个函数可以访问最初传递的topicId,所以它不会出错。第一个匿名函数会立即被调用,传入topicId,因此具有延迟的注册函数可以topicId在调用时通过闭包访问。

或者

这基本上转换为:

setTimeout(function() {
  postinsql(topicId); // topicId inside higher scope (passed to returning function)
}, 4000);

编辑:我看到了同样的答案,所以看看他的。但我没有偷他的答案!我只是忘了看。阅读解释,看看它是否有助于理解代码。

于 2016-06-01T03:27:07.023 回答
7

支持setTimeout中参数的最简单的跨浏览器解决方案:

setTimeout(function() {
    postinsql(topicId);
}, 4000)

如果您不介意不支持 IE 9 及更低版本:

setTimeout(postinsql, 4000, topicId);

setTimeout 桌面浏览器兼容性

setTimeout 移动浏览器兼容性

https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setTimeout

于 2015-06-02T18:02:56.103 回答
4

我知道它很旧,但我想在其中添加我的(首选)风味。

我认为实现这一点的一种非常易读的方法是将 传递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);
于 2013-11-20T11:07:20.423 回答
4

David Meister 的答案似乎处理了在调用 setTimeout() 之后但在调用匿名函数之前可能立即更改的参数。但是太麻烦了,也不是很明显。我发现了一种使用 IIFE(立即调用函数表达式)做几乎相同事情的优雅方式。

在下面的示例中,currentList变量被传递给 IIFE,IIFE 将其保存在其闭包中,直到调用延迟函数。即使变量currentList在显示代码后立即更改,setInterval()也会做正确的事情。

如果没有这种 IIFE 技术,setTimeout()肯定会为h2DOM 中的每个元素调用该函数,但所有这些调用将只能看到最后一个 h2元素的文本值。

<script>
  // Wait for the document to load.
  $(document).ready(function() {
  $("h2").each(function (index) {

    currentList = $(this).text();

    (function (param1, param2) {
        setTimeout(function() {
            $("span").text(param1 + ' : ' + param2 );
        }, param1 * 1000);

    })(index, currentList);
  });
</script>
于 2014-04-16T21:33:43.117 回答
4

一般来说,如果需要将函数作为带有特定参数的回调传递,则可以使用高阶函数。这在 ES6 中非常优雅:

const someFunction = (params) => () => {
  //do whatever
};

setTimeout(someFunction(params), 1000);

或者如果someFunction是一阶:

setTimeout(() => someFunction(params), 1000); 
于 2018-02-08T02:38:10.953 回答
3

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

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

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

于 2010-12-05T21:28:55.330 回答
3

我如何解决这个阶段?

就像这样:

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

于 2013-05-28T21:33:47.437 回答
3

这适用于所有浏览器(IE 很奇怪)

setTimeout( (function(x) {
return function() {
        postinsql(x);
    };
})(topicId) , 4000);
于 2014-06-19T12:45:48.903 回答
3

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

如果要求是函数并且 var 作为 parmas,那么试试这个

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

如果要求只是作为参数的变量,那么试试这个

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

你可以用 ES5 和 ES6 试试这个

于 2018-12-27T07:41:17.657 回答
3

setTimeout 是 WHAT WG 定义的 DOM 的一部分。

https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html

你想要的方法是:—</p>

handle = self.setTimeout( handler [, timeout [, arguments... ] ] )

安排超时毫秒后运行处理程序的超时。任何参数都直接传递给处理程序。

setTimeout(postinsql, 4000, topicId);

显然,IE10 支持额外的参数。或者,您可以使用setTimeout(postinsql.bind(null, topicId), 4000);,但是传递额外的参数更简单,这是可取的。

历史事实:在 VBScript 时代,在 JScript 中,setTimeout 的第三个参数是语言,作为字符串,默认为“JScript”,但可以选择使用“VBScript”。https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/platform-apis/aa741500(v%3Dvs.85)

于 2019-11-27T23:09:09.960 回答
2

您可以尝试像这样的“apply()”的默认功能,您可以在数组中传递更多数量的参数作为您的要求

function postinsql(topicId)
{
  //alert(topicId);
}
setTimeout(
       postinsql.apply(window,["mytopic"])
,500);
于 2018-06-06T10:32:41.377 回答
0

@Jiri Vetyska 感谢您的帖子,但是您的示例中有问题。我需要将悬停的目标(this)传递给超时函数,我尝试了你的方法。在 IE9 中测试 - 不起作用。我也做了一些研究,似乎这里指出的第三个参数是正在使用的脚本语言。没有提及其他参数。

所以,我按照@meder 的回答,用这段代码解决了我的问题:

$('.targetItemClass').hover(ItemHoverIn, ItemHoverOut);

function ItemHoverIn() {
 //some code here
}

function ItemHoverOut() {
    var THIS = this;
    setTimeout(
        function () { ItemHoverOut_timeout(THIS); },
        100
    );
}
function ItemHoverOut_timeout(target) {
    //do something with target which is hovered out
}

希望,这对其他人有用。

于 2013-02-27T11:13:05.357 回答
0

由于 IE 中的第三个可选参数存在问题,并且使用闭包会阻止我们更改变量(例如在循环中)并仍然达到预期的结果,我建议采用以下解决方案。

我们可以尝试像这样使用递归:

var i = 0;
var hellos = ["Hello World1!", "Hello World2!", "Hello World3!", "Hello World4!", "Hello World5!"];

if(hellos.length > 0) timeout();

function timeout() {                
    document.write('<p>' + hellos[i] + '<p>');
    i++;
    if (i < hellos.length)
        setTimeout(timeout, 500);
}

我们需要确保没有其他任何东西会改变这些变量,并且我们需要编写一个适当的递归条件来避免无限递归。

于 2013-12-23T06:17:55.280 回答
0

// 这是三个非常简单明了的答案:

function fun() {
    console.log(this.prop1, this.prop2, this.prop3);
}

let obj = { prop1: 'one', prop2: 'two', prop3: 'three' };

let bound = fun.bind(obj);

setTimeout(bound, 3000);

 // or

function funOut(par1, par2, par3) {

  return function() { 

    console.log(par1, par2, par3);

  }
};

setTimeout(funOut('one', 'two', 'three'), 5000);

 // or

let funny = function(a, b, c) { console.log(a, b, c); };

setTimeout(funny, 2000, 'hello', 'worldly', 'people');
于 2019-04-23T19:48:03.877 回答
0

您必须从函数调用中删除引号,如下所示:setTimeOut

setTimeout(postinsql(topicId),4000);
于 2020-03-12T09:12:55.687 回答
0

//Some function, with some arguments, that need to run with arguments
var a = function a(b, c, d, e){console.log(b, c, d, e);}

//Another function, where setTimeout using for function "a", this have the same arguments
var f = function f(b, c, d, e){ setTimeout(a.apply(this, arguments), 100);}

f(1,2,3,4); //run 

//Another function, where setTimeout using for function "a", but some another arguments using, in different order
var g = function g(b, c, d, e){ setTimeout(function(d, c, b){a.apply(this, arguments);}, 100, d, c, b);}

g(1,2,3,4);

于 2021-07-15T18:03:14.347 回答
-1

// 这是三个非常简单明了的答案:

function fun() {
    console.log(this.prop1, this.prop2, this.prop3);
}

let obj = { prop1: 'one', prop2: 'two', prop3: 'three' };

let bound = fun.bind(obj);

setTimeout(bound, 3000);

 // or

function funOut(par1, par2, par3) {

  return function() { 

    console.log(par1, par2, par3);

  }
};

setTimeout(funOut('one', 'two', 'three'), 5000);

 // or

let funny = function(a, b, c) { console.log(a, b, c); };

setTimeout(funny, 2000, 'hello', 'worldly', 'people');
于 2019-04-19T20:12:10.053 回答
-2

我想你想要:

setTimeout("postinsql(" + topicId + ")", 4000);
于 2009-07-27T21:16:58.507 回答
-2

回答这个问题,但通过一个带有 2 个参数的简单加法函数。

var x = 3, y = 4;

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

function delayedSum(param1, param2) {
     alert(param1 + param2); // 7
}
于 2020-02-13T17:27:30.197 回答