Как передать параметр в callbackTimeout()?

У меня есть код 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) вызывалась через некоторое время. Что я должен делать?

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

Вам нужно подавать анонимную функцию как параметр вместо строки, последний метод не должен работать даже по спецификации ECMAScript, но браузеры просто снисходительны. Это правильное решение, никогда не полагайтесь на передачу строки как "функции" при использовании setTimeout() или setInterval(), она медленнее, потому что она должна быть оценена, и это просто неправильно.

UPDATE:

Как сказал Хоблин в своих комментариях к вопросу, теперь вы можете передать аргументы функции внутри setTimeout, используя Function.prototype.bind()

Пример:

setTimeout(postinsql.bind(null, topicId), 4000);
937
ответ дан 28 июля '09 в 0:15
источник

В современных браузерах "setTimeout" получает третий параметр, который отправляется как параметр во внутреннюю функцию в конце таймера.

Пример:

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

Подробнее:

563
ответ дан 21 сент. '11 в 20:23
источник

После проведения некоторых исследований и тестирования единственная правильная реализация:

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

setTimeout передаст все дополнительные параметры вашей функции, чтобы их можно было обработать там.

Анонимная функция может работать для очень простых вещей, но внутри экземпляра объекта, где вы должны использовать "this", нет способа заставить его работать. Любая анонимная функция изменит "this", чтобы указать на окно, поэтому вы потеряете ссылку на объект.

114
ответ дан 31 окт. '12 в 1:08
источник

Это очень старый вопрос с уже "правильным" ответом, но я подумал, что упомянул еще один подход, который никто не упомянул здесь. Это скопировано и вставлено из превосходной библиотеки подчеркивания:

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

Вы можете передать столько аргументов, сколько хотите, функции, вызванной setTimeout, и в качестве дополнительного бонуса (ну, как правило, бонуса) значение аргументов, переданных вашей функции, будет заморожено при вызове setTimeout, так что если они меняют значение в какой-то момент между тем, когда вызывается setTimeout(), и когда он истекает, ну... это не так ужасно расстраивает:)

Здесь сценарий, где вы можете видеть, что я имею в виду - http://jsfiddle.net/thedavidmeister/7t2bV/

43
ответ дан 18 дек. '12 в 17:28
источник

Недавно я столкнулся с уникальной ситуацией, когда вам нужно использовать setTimeout в цикле. Понимание этого может помочь вам понять, как передавать параметры в setTimeout.

Способ 1

Используйте forEach и Object.keys, согласно 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

Использовать 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/

Способ 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, то вы можете использовать предложение Фабио:

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

Хотя я бы по-прежнему рекомендовал использовать Object.keys с forEach в ES6.

34
ответ дан 09 июля '13 в 22:58
источник

Хобблин уже прокомментировал это по этому вопросу, но это должен быть ответ на самом деле!

Использование Function.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

22
ответ дан 25 марта '13 в 19:34
источник

Некоторые ответы правильны, но сложны.

Я снова отвечаю на это, 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);
}

Синтаксис работает. Но к тому времени, когда вызывается оконечное устройство, т.е. Через 4 секунды, объект XHR может быть не таким. Поэтому важно предварительно привязать переменные.

13
ответ дан 19 янв. '14 в 9:00
источник

Заменить

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

с

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

или еще лучше, замените строковое выражение на анонимную функцию

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

EDIT:

Комментарий Brownstone неверен, это будет работать по назначению, о чем свидетельствует его запуск в консоли Firebug

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

Обратите внимание, что я согласен с другими, что вам следует избегать передачи строки в setTimeout, поскольку это вызовет eval() в строке и вместо этого передаст функцию.

9
ответ дан 28 июля '09 в 0:16
источник

Мой ответ:

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

EDIT: Я видел тот же ответ, поэтому посмотри на него. Но я не украл его ответ! Я просто забыл посмотреть. Прочтите объяснение и посмотрите, помогает ли он понять код.

7
ответ дан 01 июня '16 в 6:27
источник

Я знаю это, но я хотел добавить свой (предпочтительный) вкус к этому.

Я думаю, что довольно читаемый способ достичь этого - передать topicId функции, которая, в свою очередь, использует аргумент для ссылки на идентификатор темы внутри. Это значение не изменится, даже если 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);
3
ответ дан 20 нояб. '13 в 14:07
источник

это работает во всех браузерах (IE - странный)

setTimeout( (function(x) {
return function() {
        postinsql(x);
    };
})(topicId) , 4000);
3
ответ дан 19 июня '14 в 15:45
источник

Как я решил этот этап?

просто так:

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 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: извините, но английский это не мой родной язык!

2
ответ дан 29 мая '13 в 0:33
источник

Ответ Дэвида Майстера, похоже, позаботится о параметрах, которые могут измениться сразу после вызова setTimeout(), но до вызова анонимной функции. Но это слишком громоздко и не очень очевидно. Я обнаружил элегантный способ сделать почти то же самое, используя IIFE (сразу inviked выражение функции).

В приведенном ниже примере переменная currentList передается в IIFE, которая сохраняет ее при ее закрытии, пока не будет вызвана функция delayed. Даже если переменная currentList изменяется сразу после показанного кода, setInterval() выполнит правильную работу.

Без этого метода IIFE функция setTimeout() определенно будет вызвана для каждого элемента h2 в DOM, но все эти вызовы будут видеть только текстовое значение last 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>
2
ответ дан 17 апр. '14 в 0:33
источник

Обратите внимание, что причина, по которой topicId была "не определена" в сообщении об ошибке, заключается в том, что она существовала как локальная переменная, когда был запущен setTimeout, но не тогда, когда произошел отложенный вызов postinsql. Особенно важно обратить внимание на переменный ресурс, особенно когда вы пытаетесь что-то вроде передачи "this" в качестве ссылки на объект.

Я слышал, что вы можете передать topicId в качестве третьего параметра функции setTimeout. Не так много деталей, но я получил достаточно информации, чтобы заставить его работать, и это успешно работает в Safari. Я не знаю, что они означают о "миллисекундовой ошибке". Посмотрите здесь:

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

2
ответ дан 06 дек. '10 в 0:28
источник

Вы можете попробовать по умолчанию функциональность 'apply()' что-то вроде этого, вы можете передать больше аргументов в качестве вашего требования в массиве

function postinsql(topicId)
{
  //alert(topicId);
}
setTimeout(
       postinsql.apply(window,["mytopic"])
,500);
0
ответ дан 06 июня '18 в 13:32
источник

В общем случае, если вам нужно передать функцию в качестве обратного вызова с определенными параметрами, вы можете использовать функции более высокого порядка. Это довольно элегантно с ES6:

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

setTimeout(someFunction(params), 1000);

Или, если someFunction - первый заказ:

setTimeout(() => someFunction(params), 1000); 
0
ответ дан 08 февр. '18 в 5:38
источник

Я думаю, вы хотите:

setTimeout("postinsql(" + topicId + ")", 4000);
0
ответ дан 28 июля '09 в 0:16
источник

Поскольку проблема с третьим оплотронным параметром в 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);
}

Нам нужно убедиться, что ничего не изменит эти переменные, и мы напишем правильное условие рекурсии, чтобы избежать бесконечной рекурсии.

0
ответ дан 23 дек. '13 в 9:17
источник

@Jiri Vetyska благодарит за сообщение, но в вашем примере что-то не так. Мне нужно было передать цель, которая зависла (это) до функции времени ожидания, и я попробовал ваш подход. Протестировано в IE9 - не работает. Я также сделал некоторые исследования, и кажется, что в качестве здесь третий параметр используется для используемого языка script. Нет никаких дополнительных параметров.

Итак, я последовал за ответом @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
}

Надеюсь, это полезно для кого-то еще.

0
ответ дан 27 февр. '13 в 14:13
источник