Одна из возможностей заключается в использовании сериализации:
Apache Commons предоставляет SerializationUtils
setTimeout(function() {
postinsql(topicId);
}, 4000)
Вам нужно подавать анонимную функцию как параметр вместо строки, последний метод не должен работать даже по спецификации ECMAScript, но браузеры просто снисходительны. Это правильное решение, никогда не полагайтесь на передачу строки как «функции» при использовании setTimeout()
или setInterval()
, она медленнее, потому что она должна быть оценена, и это просто неправильно.
UPDATE:
Как сказал Хоблин в своих комментариях к вопросу, теперь вы можете передать аргументы функции внутри setTimeout с помощью Function.prototype.bind()
Пример:
setTimeout(postinsql.bind(null, topicId), 4000);
Как я решил этот этап?
так же:
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: извините, но английский это не мой родной язык!
Обратите внимание, что причина, по которой topicId была «не определена» в сообщении об ошибке, заключается в том, что она существовала как локальная переменная, когда был запущен setTimeout, но не тогда, когда произошел отложенный вызов postinsql. Важное значение имеет значение переменной, особенно когда вы пытаетесь что-то вроде передачи «this» в качестве ссылки на объект.
Я слышал, что вы можете передать topicId в качестве третьего параметра функции setTimeout. Не так много деталей, но я получил достаточно информации, чтобы заставить ее работать, и она успешна в Safari. Я не знаю, что они означают о «миллисекундовой ошибке». Проверьте это здесь:
Это очень старый вопрос с уже «правильным» ответом, но я думал, что упомянул еще один подход, который никто не упомянул здесь. Это скопировано и вставлено из превосходной библиотеки underscore :
_.delay = function(func, wait) {
var args = slice.call(arguments, 2);
return setTimeout(function(){ return func.apply(null, args); }, wait);
};
Вы можете передать столько аргументов, сколько хотите, для функции, вызванной setTimeout и в качестве дополнительного бонуса (ну, как правило, бонуса) значение аргументов, переданных вашей функции, блокируется при вызове setTimeout, поэтому, если они изменяют значение в какой-то момент между вызовом 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 может быть не таким. Поэтому важно предварительно привязать переменные .
.bind
не будет работать для IE8 и ниже [ref: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… ]. Я закончил использование решения Schien: stackoverflow.com/a/21213723/1876899
– cjspurgeon
22 April 2014 в 19:35
bind
, вы также находитесь в среде, которая предлагает Object.keys
и forEach
. Вы можете потерять цикл for и получить «бесплатный». (как у двух птиц с одним камнем, свободным от ресурсов).
– Sukima
8 July 2014 в 13:08
async
( github.com/caolan/async ). Мы широко используем его в Sails и добились отличных результатов за последние 2 года. Он предоставляет методы как параллельно, так и последовательно для асинхронных forEach
, map
, reduce
и т. Д.
– mikermcneil
23 October 2015 в 12:26
Я знаю, что он старый, но я хотел добавить свой (предпочтительный) вкус к этому.
Я думаю, что довольно читаемый способ добиться этого - передать функцию 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» получает третий параметр, который отправляется как параметр для внутренней функции в конце таймера.
Пример:
var hello = "Hello World";
setTimeout(alert, 1000, hello);
Подробнее:
Ответ Дэвида Майстера, похоже, позаботится о параметрах, которые могут измениться сразу после вызова setTimeout (), но до вызова анонимной функции. Но это слишком громоздко и не очень очевидно. Я обнаружил элегантный способ сделать почти то же самое, используя IIFE (сразу inviked выражение функции).
В приведенном ниже примере переменная 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>
После выполнения некоторых исследований и тестирования единственная правильная реализация:
setTimeout(yourFunctionReference, 4000, param1, param2, paramN);
setTimeout передаст все дополнительные параметры вашей функции, чтобы их можно было обработать там.
анонимная функция может работать для очень простых вещей, но в пределах экземпляра объекта, где вы должны использовать «это», нет способа заставить его работать. Любая анонимная функция изменит «это», чтобы указать на окно, поэтому вы потеряете ссылку на объект.
var that = this; setTimeout( function() { that.foo(); }, 1000);
– Ed Williams
7 June 2013 в 07:41
В общем случае, если вам нужно передать функцию в качестве обратного вызова с определенными параметрами, вы можете использовать функции более высокого порядка. Это довольно элегантно с ES6:
const someFunction = (params) => () => {
//do whatever
};
setTimeout(someFunction(params), 1000);
Или если someFunction
- первый порядок:
setTimeout(() => someFunction(params), 1000);
Хобблин уже прокомментировал это по этому вопросу, но на самом деле это должен быть ответ!
Использование 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
setTimeout(postinsql.bind(this, topicId), 4000);
– Giuseppe Galano
11 December 2013 в 16:29
bind
. Это действительно делает для некоторого читаемого кода.
– Sukima
8 July 2014 в 13:05
Самое простое решение для кросс-браузера для поддержки параметров в setTimeout:
setTimeout(function() {
postinsql(topicId);
}, 4000)
Если вы не возражаете против поддержки IE 9 и ниже:
setTimeout(postinsql, 4000, topicId);
[/g1]
[/g2]
https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/ SetTimeout
Замените
setTimeout("postinsql(topicId)", 4000);
на
setTimeout("postinsql(" + topicId + ")", 4000);
или еще лучше, замените строковое выражение на анонимную функцию
setTimeout(function () { postinsql(topicId); }, 4000);
EDIT:
Комментарий Браунстоуна неверен, это будет работать так, как было показано, как показано на рисунке ниже, в этом случае в консоли Firebug
(function() {
function postinsql(id) {
console.log(id);
}
var topicId = 3
window.setTimeout("postinsql(" + topicId + ")",4000); // outputs 3 after 4 seconds
})();
Обратите внимание, что я согласен с другими, что вам следует избегать передачи строка в setTimeout
, так как это вызовет eval()
в строке и вместо этого передаст функцию.
Я думаю, что вы хотите:
setTimeout("postinsql(" + topicId + ")", 4000);
это работает во всех браузерах (IE - странный)
setTimeout( (function(x) {
return function() {
postinsql(x);
};
})(topicId) , 4000);
Поскольку проблема с третьим параметром optonal в 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);
}
Нам нужно убедиться, что ничего не изменит эти переменные и мы напишем правильное условие рекурсии, чтобы избежать бесконечной рекурсии.
Вы можете попробовать использовать функции «apply ()» по умолчанию, вы можете передать большее количество аргументов в качестве вашего требования в массиве
function postinsql(topicId)
{
//alert(topicId);
}
setTimeout(
postinsql.apply(window,["mytopic"])
,500);
@Jiri Vetyska благодарит за сообщение, но в вашем примере что-то не так. Мне нужно было передать цель, которая зависла (это) до функции времени ожидания, и я попробовал ваш подход. Протестировано в 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
}
Надеюсь, это полезно для кого-то еще.
window.setTimeout
является методом DOM и, как таковой, не определяется спецификацией ECMAScript. Передача строки всегда работала в браузерах и была стандартом de facto i> - на самом деле возможность добавления объекта функции была добавлена позже, с JavaScript 1.2 - она явно является частью спецификации HTML5 ( [д0] whatwg.org/specs/web-apps/current-work/multipage/… [/ д0]). Однако использование строки вместо объекта функции обычно считается плохим, потому что это по существу форма задержкиeval()
. – Miles 27 July 2009 в 22:41