setTimeout / clearTimeoutの問題


103

スタートページに行くようなページを作ってみます。10秒間非アクティブ(ユーザーがどこもクリックしていない)。残りはjQueryを使用していますが、テスト関数のset / clearは純粋なJavaScriptです。

私の欲求不満の中で、私はこの関数のようなものになり、ページ上の任意のクリックで呼び出すことができると思いました。タイマーは正常に起動しますが、クリックしてもリセットされません。最初の10秒以内に関数が5回呼び出されると、5つのアラートが表示されます... clearTimeoutなし...

function endAndStartTimer() {
    window.clearTimeout(timer);
    var timer;
    //var millisecBeforeRedirect = 10000; 
    timer = window.setTimeout(function(){alert('Hello!');},10000); 
}

だれかがトリックを実行するいくつかのコード行を取得しましたか?-任意のクリック停止で、タイマーをリセットして開始します。-タイマーがヒットしたとき。10秒で何かします。

回答:


226

関数のtimer 外で宣言する必要があります。それ以外の場合は、関数を呼び出すたびに新しい変数が取得されます。

var timer;
function endAndStartTimer() {
  window.clearTimeout(timer);
  //var millisecBeforeRedirect = 10000; 
  timer = window.setTimeout(function(){alert('Hello!');},10000); 
}

それは前に二回呼び出されることを避け、ように、時間を呼び出しタイムアウトフード変数をクリアするには、この場合には、必要なプラス1 1ので
サンディエゴFavero

46

問題は、timer変数がローカルであり、その値が各関数呼び出しの後に失われることです。

あなたはそれを永続化する必要があります、あなたはそれを関数の外に置くことができます、またはあなたがグローバルとして変数を公開したくないなら、あなたはクロージャーにそれを保存することができます:

var endAndStartTimer = (function () {
  var timer; // variable persisted here
  return function () {
    window.clearTimeout(timer);
    //var millisecBeforeRedirect = 10000; 
    timer = window.setTimeout(function(){alert('Hello!');},10000); 
  };
})();

15

これは、timerが関数のローカル変数であるためです。

関数の外で作成してみてください。


6

これを反応で使用する方法:

class Timeout extends Component {
  constructor(props){
    super(props)

    this.state = {
      timeout: null
    }

  }

  userTimeout(){
    const { timeout } = this.state;
    clearTimeout(timeout);
    this.setState({
      timeout: setTimeout(() => {this.callAPI()}, 250)
    })

  }
}

たとえば、ユーザーが入力をやめた後にのみAPIを呼び出したい場合に役立ちます。userTimeout関数は、onKeyUpを介して入力にバインドできます。


1
これは私が数時間探していたものです、ありがとう。この種の結果を実現するためのより良い方法があるのか​​とただ思っていましたか?
Nikasv

1
@nikasvスロットルとデバウンスは、2つの代替手段です。medium.com
@ _ jh3y

2

これがいくつかの良い習慣のコーディング規則に違反しているかどうかはわかりませんが、通常は次のようになります。

if(typeof __t == 'undefined')
        __t = 0;
clearTimeout(__t);
__t = setTimeout(callback, 1000);

これにより、関数からタイマーを宣言する必要がなくなります。

編集:これはまた、呼び出しごとに新しい変数を宣言しませんが、常に同じ変数をリサイクルします。

お役に立てれば。


0

これはうまくいきます。保留イベントを処理するために私が作成したマネージャーです。ホールドのためのイベントとあなたが手放したときのためのイベントがあります。

function onUserHold(element, func, hold, clearfunc) {
    //var holdTime = 0;
    var holdTimeout;

    element.addEventListener('mousedown', function(e) {
        holdTimeout = setTimeout(function() {
            func();
            clearTimeout(holdTimeout);
            holdTime = 0;
        }, hold);
        //alert('UU');
    });

    element.addEventListener('mouseup', clearTime);
    element.addEventListener('mouseout', clearTime);

    function clearTime() {
        clearTimeout(holdTimeout);
        holdTime = 0;
        if(clearfunc) {
            clearfunc();
        }
    }
}

elementパラメーターは、保持するパラメーターです。funcパラメータは、パラメータholdで指定されたミリ秒数の間保持されると起動します。clearfunc paramはオプションであり、指定されている場合、ユーザーが要素に移動するか要素を離れると起動されます。必要な機能を取得するためにいくつかの回避策を実行することもできます。楽しい!:)


0

ドロップダウンメニューにJqueryを使用する実用的な例!#IconLoggedinUxExternalの上にマウスを置くと、div#ExternalMenuLoginが表示され、タイムアウトを設定してdiv#ExternalMenuLoginを非表示にします

div#ExternalMenuLoginにマウスオーバーすると、タイムアウトがキャンセルされます。div#ExternalMenuLoginでマウスアウトすると、タイムアウトが設定されます。

ここでのポイントは、タイムアウトを設定する前に常にclearTimeoutを呼び出すことです。これにより、二重呼び出しを回避できます。

var ExternalMenuLoginTO;
$('#IconLoggedinUxExternal').on('mouseover mouseenter', function () {

    clearTimeout( ExternalMenuLoginTO )
    $("#ExternalMenuLogin").show()
});

$('#IconLoggedinUxExternal').on('mouseleave mouseout', function () {

    clearTimeout( ExternalMenuLoginTO )    
    ExternalMenuLoginTO = setTimeout(
        function () {

            $("#ExternalMenuLogin").hide()

        }
        ,1000
    );
    $("#ExternalMenuLogin").show()
});

$('#ExternalMenuLogin').on('mouseover mouseenter', function () {

    clearTimeout( ExternalMenuLoginTO )
});
$('#ExternalMenuLogin').on('mouseleave mouseout', function () {

    clearTimeout( ExternalMenuLoginTO )
    ExternalMenuLoginTO = setTimeout(
        function () {

            $("#ExternalMenuLogin").hide()

        }
        ,500
    );
});
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.