web-dev-qa-db-ja.com

SetTimeout()コールバックにパラメータを渡すにはどうすればいいですか?

次のような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)関数を呼び出したいです。私は何をすべきか?

752
Zeeshan Rang
setTimeout(function() {
    postinsql(topicId);
}, 4000)

あなたは文字列の代わりにパラメータとして無名関数を供給する必要があります、後者のメソッドはECMAScript仕様に従ってさえ働くべきではありませんが、ブラウザは単に寛大です。これは適切な解決策です。setTimeout()またはsetInterval()を使用するときに文字列を「関数」として渡すことに頼らないでください。評価しなければならず、正しくないので時間がかかります。

更新:

Hobblinがその質問へのコメントで述べたように、Function.prototype.bind()を使用してsetTimeout内で関数に引数を渡すことができます。

例:

setTimeout(postinsql.bind(null, topicId), 4000);
1039
meder omuraliev

最近のブラウザでは、 "setTimeout"はタイマーの終了時に内部関数へのパラメータとして送信される3番目のパラメータを受け取ります。

例:

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

もっと詳しく

645
Fabio Phms

いくつかの調査とテストを行った後、唯一の正しい実装は以下のとおりです。

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

setTimeoutは、追加のパラメータをすべて関数に渡して、そこで処理できるようにします。

匿名関数は非常に基本的なもののために働くことができますが、 "this"を使わなければならないオブジェクトのインスタンスの中では、それを働かせる方法はありません。匿名の関数はすべて "this"をwindowを指すように変更するので、あなたはあなたのオブジェクト参照を失うことになります。

131
Jiri Vetyska

これは非常に古くからある質問で、すでに「正しい」答えがありますが、ここでは誰も言及していない別のアプローチに言及することにしました。これは、優れた アンダースコア ライブラリからコピーして貼り付けます。

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

SetTimeout および によって呼び出される関数には、追加のボーナスとして(通常はボーナスとして)必要なだけ引数を渡すことができます。setTimeoutを呼び出すと、関数に渡される引数の値は固定されますそのため、setTimeout()が呼び出されてからタイムアウトになるまでの間に値が変更されても、それほどひどくイライラすることはありません。

ここにいじる ここで、私の言っていることを見ることができる。

44
David Meister

私は最近、 loop setTimeoutを使う必要があるという独特の状況に遭遇しました。これを理解することはsetTimeoutにパラメータを渡す方法を理解するのに役立ちます。

方法1

Sukimaの 提案 に従って、forEachObject.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を気にしないのであれば、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ではforEachObject.keysの併用をお勧めします。

37
David Sherret

Hobblinはすでにこの問題についてコメントしていますが、それは本当に答えになるはずです。

Function.prototype.bind()を使用するのがこれを行うための最もクリーンで最も柔軟な方法です(thisコンテキストを設定できるという追加のボーナスと共に):

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

詳細については、これらのMDNリンクを参照してください。
https://developer.mozilla.org/en/docs/DOM/window.setTimeout#highlighter_547041https://developer.mozilla.org/en/docs/JavaScript/Reference/ Global_Objects/Function/bind#With_setTimeout

22
dain

いくつかの答えは正しいですが複雑です。

私はまだこの質問を正確に解決するために過度に複雑なコードに出くわすので、私は4年後に、これに再び答えています。そこにIS優雅な解決策があります。

まず第一に、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オブジェクトは同じではないかもしれません。したがって、 変数を事前バインドすることが重要です

16
Schien

私の答え:

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

説明:

作成された無名関数は別の無名関数を返します。この関数は最初に渡されたtopicIdにアクセスできるので、エラーにはなりません。最初の無名関数はすぐに呼び出され、topicIdを渡します。そのため、遅延のある登録済み関数は、呼び出し時にクロージャを通じてtopicIdにアクセスできます。

OR

これは基本的に次のように変換されます。

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

編集:私は同じ答えを見たので、彼を見てください。しかし、私は彼の答えを盗みませんでした!私は見るのを忘れました。説明を読み、それがコードを理解するのに役立つかどうかを確認してください。

10
user4447514

交換する

 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()を呼び出し、代わりに関数を渡すからです。

9
Russ Cam

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

6

私はそれが古いことを知っていますが、私はこれに私の(好みの)味を加えたいと思いました。

これを達成するためのかなり読みやすい方法は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);
3
Dominic

これはすべてのブラウザで動作します(IEはおかしなことです)。

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

David Meisterによる答えは、setTimeout()を呼び出した直後で、無名関数が呼び出される前に変更される可能性があるパラメータを考慮しているようです。しかし、それは面倒すぎてあまり明白ではありません。私はIIFE(すぐに呼び出される関数式)を使ってほぼ同じことをする優雅な方法を発見しました。

以下の例では、currentList変数がIIFEに渡され、遅延関数が呼び出されるまで、変数は閉じて保存されます。表示されたコードの直後に変数currentListが変わっても、setInterval()は正しいことをします。

このIIFEテクニックがなければ、setTimeout()関数はDOMの各h2要素に対して確実に呼び出されますが、それらの呼び出しはすべて 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>
3
Gurjeet Singh

一般に、特定のパラメータを持つコールバックとして関数を渡す必要がある場合は、高階関数を使用できます。これはES6ではかなりエレガントです。

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

setTimeout(someFunction(params), 1000);

someFunctionが1次の場合

setTimeout(() => someFunction(params), 1000); 
2
John Hartman

どのように私はこの段階を解決しましたか?

ちょうどそのように:

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:申し訳ありませんが英語それは私の母国語ではありません!

2
Anonymous0day

エラーメッセージに従ってtopicIdが「定義されていない」理由は、setTimeoutが実行されたときにローカル変数として存在していたが、postinsqlへの遅延呼び出しが発生したときではないことに注意してください。特に「this」をオブジェクト参照として渡すようなことを試みるときは、可変寿命が特に注意を払うために重要です。

SetTimeout関数の3番目のパラメータとしてtopicIdを渡すことができると聞きました。詳細は説明されていませんが、それを機能させるのに十分な情報が得られました。Safariでは成功しています。私は彼らが "ミリ秒エラー"についてどういう意味を知らない。ここでそれをチェックしてください。

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

2
billy

あなたがパラメータとして変数を渡したい場合はこれを試してみましょう

必要条件がparmasとしてのfunctionとvarであるならば、これを試してください

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

要件がパラメータとしての変数にすぎない場合は、これを試してください

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

あなたはES5とES6でこれを試すことができます

2
mad Man

あなたはこのような 'apply()'のデフォルト機能を試すことができます、あなたは配列としてあなたの要求としてより多くの引数を渡すことができます

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

//これらは非常に単純で簡潔な3つの答えです。

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

IEの3番目のoptonalパラメータに問題があり、クロージャを使用すると、変数を変更して(たとえばループ内で)希望どおりの結果が得られないため、次の解決策をお勧めします。

このように再帰を使ってみることができます。

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

他に何もこれらの変数を変更しないこと、そして無限再帰を避けるために適切な再帰条件を書くことを確かめる必要があります。

次のようにsetTimeoutコールバック関数にパラメータを渡すことができます。

setTimeout(関数、ミリ秒、パラメータ1、パラメータ2、...)

例えば。

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

function alertMsg(message) {
    alert(message)
}
0
Jatin Verma

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

願って、これは他の誰かにとって便利です。

0
Vladislav