How can I pass a parameter to a setTimeout() callback?

Viewed 715444

I have some JavaScript code that looks like:

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

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

I get an error that topicId is not defined Everything was working before I used the setTimeout() function.

I want my postinsql(topicId) function to be called after some time. What should I do?

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

You need to feed an anonymous function as a parameter instead of a string, the latter method shouldn't even work per the ECMAScript specification but browsers are just lenient. This is the proper solution, don't ever rely on passing a string as a 'function' when using setTimeout() or setInterval(), it's slower because it has to be evaluated and it just isn't right.

UPDATE:

As Hobblin said in his comments to the question, now you can pass arguments to the function inside setTimeout using Function.prototype.bind().

Example:

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

You can pass the parameter to the setTimeout callback function as:

setTimeout(function, milliseconds, param1, param2, ...)

eg.

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

function alertMsg(message) {
    alert(message)
}

I know its been 10 yrs since this question was asked, but still, if you have scrolled till here, i assume you're still facing some issue. The solution by Meder Omuraliev is the simplest one and may help most of us but for those who don't want to have any binding, here it is:

  1. Use Param for setTimeout
setTimeout(function(p){
//p == param1
},3000,param1);
  1. Use Immediately Invoked Function Expression(IIFE)
let param1 = 'demon';
setTimeout(function(p){
    // p == 'demon'
},2000,(function(){
    return param1;
})()
);
  1. Solution to the question
function statechangedPostQuestion()
{
  //alert("statechangedPostQuestion");
  if (xmlhttp.readyState==4)
  {
    setTimeout(postinsql,4000,(function(){
        return xmlhttp.responseText;
    })());
  }
}

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

Replace

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

with

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

or better still, replace the string expression with an anonymous function

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

EDIT:

Brownstone's comment is incorrect, this will work as intended, as demonstrated by running this in the Firebug console

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

Note that I'm in agreeance with others that you should avoid passing a string to setTimeout as this will call eval() on the string and instead pass a function.

I know it's old but I wanted to add my (preferred) flavour to this.

I think a pretty readable way to achieve this is to pass the topicId to a function, which in turn uses the argument to reference the topic ID internally. This value won't change even if topicId in the outside will be changed shortly after.

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

or short:

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

In general, if you need to pass a function as a callback with specific parameters, you can use higher order functions. This is pretty elegant with ES6:

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

setTimeout(someFunction(params), 1000);

Or if someFunction is first order:

setTimeout(() => someFunction(params), 1000); 

if you want to pass variable as param lets try this

if requirement is function and var as parmas then try this

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

if requirement is only variables as a params then try this

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

You can try this with ES5 and ES6

setTimeout is part of the DOM defined by WHAT WG.

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

The method you want is:—

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

Schedules a timeout to run handler after timeout milliseconds. Any arguments are passed straight through to the handler.

setTimeout(postinsql, 4000, topicId);

Apparently, extra arguments are supported in IE10. Alternatively, you can use setTimeout(postinsql.bind(null, topicId), 4000);, however passing extra arguments is simpler, and that's preferable.

Historical factoid: In days of VBScript, in JScript, setTimeout's third parameter was the language, as a string, defaulting to "JScript" but with the option to use "VBScript". https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/platform-apis/aa741500(v%3Dvs.85)

You can try default functionality of 'apply()' something like this, you can pass more number of arguments as your requirement in the array

function postinsql(topicId)
{
  //alert(topicId);
}
setTimeout(
       postinsql.apply(window,["mytopic"])
,500);

//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);

// These are three very simple and concise answers:

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');

// These are three very simple and concise answers:

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');

You have to remove quotes from your setTimeOut function call like this:

setTimeout(postinsql(topicId),4000);

I think you want:

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

Answering the question but by a simple addition function with 2 arguments.

var x = 3, y = 4;

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

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