web-dev-qa-db-ja.com

setTimeout()を使用して関数を呼び出す

簡単に言えば...

どして

setTimeout('playNote('+currentaudio.id+', '+noteTime+')', delay);

完全に機能し、指定された遅延後に関数を呼び出しますが、

setTimeout(playNote(currentaudio.id,noteTime), delay);

関数playNoteをすべて同時に呼び出しますか?

(これらのsetTimeout()はforループ内にあります)

または、説明が読みにくい場合、2つの機能の違いは何ですか?

38
Alex Hwang

リストする最初のフォームは、delayの最後の文字列を評価するため、機能します。 eval()を使用することは一般に良い考えではないため、これを避ける必要があります。

関数呼び出し演算子_()_で関数オブジェクトをすぐに実行するため、2番目の方法は機能しません。最終的には、playNote(...)の形式を使用するとplayNoteがすぐに実行されるため、遅延の最後に何も起こりません。

代わりに、匿名関数をsetTimeoutに渡す必要があるため、正しい形式は次のとおりです。

_setTimeout(function() { playNote(currentaudio.id,noteTime) }, delay);
_

関数式全体にsetTimeoutを渡すため、匿名関数を保持し、遅延の最後にのみ実行することに注意してください。

参照はすぐには実行されないため、setTimeout参照を渡すこともできますが、引数を渡すことはできません。

_setTimeout(playNote, delay);
_

注:

繰り返しイベントの場合、setInterval()を使用できます。また、setInterval()を変数に設定して、変数を使用できます。 clearInterval()で間隔を停止します。

forループでsetTimeout()を使用すると言います。多くの場合、再帰関数でsetTimeout()を使用することをお勧めします。これは、forループでは、setTimeout()で使用される変数は、setTimeout()が開始したときの変数ではなく、後の変数であるためです。関数が起動されるときの遅延。

この問題全体を回避するには、再帰関数を使用してください。

再帰を使用して可変遅延時間を処理する:

_  // Set original delay
var delay = 500;

  // Call the function for the first time, to begin the recursion.
playNote(xxx, yyy);

  // The recursive function
function playNote(theId, theTime)
{
    // Do whatever has to be done
    // ...

    // Have the function call itself again after a delay, if necessary
    //   you can modify the arguments that you use here. As an
    //   example I add 20 to theTime each time. You can also modify
    //   the delay. I add 1/2 a second to the delay each time as an example.
    //   You can use a condition to continue or stop the recursion

    delay += 500;

    if (condition)
    { setTimeout(function() { playNote(theID, theTime + 20) }, delay); }
}
_
67
Peter Ajtai

これを試して。

setTimeout(function() { playNote(currentaudio.id,noteTime) }, delay);
7
Daniel A. White

文字列タイムアウトを使用しないでください。有効なのはevalで、これは悪いことです。 _currentaudio.id_およびnoteTimeを自分自身の文字列表現に変換し、コード内に隠しているため、機能します。これは、それらの値が値を再作成するJavaScriptリテラル構文を生成するtoString() sを持っている場合にのみ機能します。これはNumberに当てはまります。

_setTimeout(playNote(currentaudio.id, noteTime), delay);
_

それは関数呼び出しです。 playNoteがすぐに呼び出され、関数の戻り値(おそらくundefined)がsetTimeout()に渡されます。

他の回答が言及しているように、クロージャーとともにインライン関数式を使用して、currentaudioおよびnoteTimeを参照できます。

_setTimeout(function() {
    playNote(currentaudio.id, noteTime);
}, delay);
_

ただし、ループ内にあり、currentaudioまたはnoteTimeがループのたびに異なる場合は、クロージャーループの問題が発生します。すべてのタイムアウトで同じ変数が参照されるため、毎回同じ値、つまりループが以前に終了したときに変数に残された値を取得すると呼ばれます。

anotherクロージャーでこれを回避し、ループの各反復に対して変数の値のコピーを取得できます。

_setTimeout(function() {
    return function(currentaudio, noteTime) {
        playNote(currentaudio.id, noteTime);
    };
}(currentaudio, noteTime), delay);
_

しかし、これは少しbitいものになっています。より良いのは_Function#bind_で、これは関数を部分的に適用します:

_setTimeout(playNote.bind(window, currentaudio.id, noteTime), delay);
_

windowthisの値を関数内に設定するためのもので、これはbind()の機能であり、ここでは必要ありません。)

ただし、これはECMAScript第5版の機能であり、すべてのブラウザーがまだサポートしているわけではありません。したがって、それを使用する場合は、最初にサポートでハッキングする必要があります。

_// Make ECMA262-5 Function#bind work on older browsers
//
if (!('bind' in Function.prototype)) {
    Function.prototype.bind= function(owner) {
        var that= this;
        if (arguments.length<=1) {
            return function() {
                return that.apply(owner, arguments);
            };
        } else {
            var args= Array.prototype.slice.call(arguments, 1);
            return function() {
                return that.apply(owner, arguments.length===0? args : args.concat(Array.prototype.slice.call(arguments)));
            };
        }
    };
}
_
4
bobince

2番目のものはplayNote関数firstを呼び出してから、戻り値をsetTimeoutに渡すように指示しているためです。

1
dgnorton

Javascriptがコードを実行するタイミングと、何かの実行を待機するタイミングを理解するのに役立つ場合があります。

let foo2 = function foo(bar=baz()){ console.log(bar); return bar()}

  • Javascriptが最初に実行するのは、関数コンストラクターであり、関数オブジェクトを作成します。 _=>_構文の関数キーワード構文を使用すると、同様の( ただし同一ではない )結果が得られます。
  • 作成されたばかりの関数は、変数_foo2_に割り当てられます
  • この時点では、他には何も実行されていません。他の関数は呼び出されていません(bazbarも、値も参照されていません。しかし、関数内で構文がチェックされています。
  • fooまたは_foo2_をsetTimeoutに渡すと、タイムアウト後に、foo()と同じように関数が呼び出されます。 (引数がfooに渡されないことに注意してください。これは、setTimeoutがデフォルトで引数を渡さないためです 可能ですが ですが、それらの引数はタイムアウトになるのではなく、タイムアウトになる)
  • Fooが呼び出された後、デフォルトの引数が評価されます。引数を渡さずにfooを呼び出したため、barのデフォルトが評価されます。 (引数を渡した場合、これは起こりませんでした)
  • barのデフォルト引数を評価する際、最初のjavascriptはbazという名前の変数を探します。見つかった場合は、関数として呼び出します。それが機能する場合、戻り値をbarに保存します。
  • これで、関数の本体が評価されます。
  • Javascriptは変数barを検索し、結果とともにconsole.logを呼び出します。これはbarを呼び出しません。ただし、代わりにbar()として呼び出された場合、barが最初に実行され、その後bar()の戻り値が_console.log_に渡されます。 javascriptは、呼び出している関数の引数の値を取得していることに注意してくださいbefore関数を呼び出し、関数をルックアップする前でもそれは存在し、実際に機能です。
  • Javascriptはbarを再度検索し、関数として呼び出します。それが機能する場合、値はfoo()の結果として返されます

したがって、関数本体とデフォルトの引数はすぐには呼び出されませんが、他のすべては呼び出されます。同様に、関数呼び出し(つまり_()_)を実行すると、その関数もすぐに実行されます。ただし、関数を呼び出す必要はありません。括弧を省略すると、その関数を渡し、後で呼び出すことができます。ただし、その欠点は、関数の呼び出しに使用する引数を指定できないことです。また、javascriptは関数の括弧before内ですべてを実行し、関数を呼び出すか、関数が保存されている変数を検索します。

0
Garrett Motzner