Вопрос

У меня есть код 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() {
    postinsql(topicId);
}, 4000)

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

ОБНОВЛЯТЬ:

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

Пример:

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

Другие советы

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

Пример:

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

Более подробная информация:

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

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

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

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

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

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

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

Вот скрипка где вы можете увидеть, что я имею в виду.

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

Способ 1

Использовать forEach и 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);
});

Я рекомендую этот метод.

Способ 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.

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

С использованием 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

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

Я отвечаю на этот вопрос снова, 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 может уже не быть прежним.Поэтому важно предварительно привязать переменные.

Мой ответ:

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

РЕДАКТИРОВАТЬ:Я видел тот же ответ, так что посмотрите на него.Но я не украл его ответ!Я просто забыл посмотреть.Прочтите объяснение и посмотрите, поможет ли оно понять код.

Заменять

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

с

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

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

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

РЕДАКТИРОВАТЬ:

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

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

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

Самое простое кроссбраузерное решение для поддержки параметров в setTimeout:

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

Если вы не против отказаться от поддержки IE 9 и более ранних версий:

setTimeout(postinsql, 4000, topicId);

setTimeout desktop browser compatibility

setTimeout mobile browser compatibility

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

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

Я думаю, что довольно читабельный способ добиться этого - передать 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);

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

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

Без этой техники IIFE setTimeout() функция обязательно будет вызываться для каждого h2 элемент в DOM, но все эти вызовы будут видеть только текстовое значение последний 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>

это работает во всех браузерах (IE - чудак)

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

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

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

setTimeout(someFunction(params), 1000);

Или если someFunction это первый заказ:

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

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

Я слышал, что вы можете передать themeId в качестве третьего параметра функции 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 );

Надеюсь, это может помочь!

пс:извините, но английский — не мой родной язык!

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

если требованием является функция и var в качестве параметра, попробуйте это

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

если в качестве параметров требуются только переменные, попробуйте это

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

Вы можете попробовать это с ES5 и ES6.

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

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

Вы можете передать параметр в функцию обратного вызова setTimeout следующим образом:

setTimeout(функция, миллисекунды, параметр1, параметр2, ...)

например.

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

function alertMsg(message) {
    alert(message)
}

@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
}

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

Поскольку в 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);
}

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

// Это три очень простых и кратких ответа:

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

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

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

// Это три очень простых и кратких ответа:

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');
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top