99

私が所有していないライブラリ コードと対話する Javascript を作成していて、(合理的に) 変更することはできません。一連の時間制限のある質問で次の質問を表示するために使用される Javascript タイムアウトを作成します。これは完全に難読化されているため、実際のコードではありません。ライブラリが行っていることは次のとおりです。

....
// setup a timeout to go to the next question based on user-supplied time
var t = questionTime * 1000
test.currentTimeout = setTimeout( showNextQuestion(questions[i+1]), t );

questionTime * 1000によって作成されたタイマーに問い合わせることで、画面上に進行状況バーを表示したいと考えていますsetTimeout。唯一の問題は、これを行う方法がないように見えることです。getTimeout私が見逃している機能はありますか?私が見つけることができる Javascript タイムアウトに関する唯一の情報は、 による作成setTimeout( function, time)と による削除のみに関連していclearTimeout( id )ます。

タイムアウトが発生するまでの残り時間、またはタイムアウトが呼び出されてからの経過時間を返す関数を探しています。私の進行状況バーコードは次のようになります。

var  timeleft = getTimeout( test.currentTimeout ); // I don't know how to do this
var  $bar = $('.control .bar');
while ( timeleft > 1 ) {
    $bar.width(timeleft / test.defaultQuestionTime * 1000);
}

tl;dr: javascript の setTimeout() までの残り時間を調べるにはどうすればよいですか?


これが私が現在使用しているソリューションです。私は、テストを担当するライブラリ セクションを調べて、コードを解読しました (ひどい、私の許可に反して)。

// setup a timeout to go to the next question based on user-supplied time
var t = questionTime * 1000
test.currentTimeout = mySetTimeout( showNextQuestion(questions[i+1]), t );

ここに私のコードがあります:

// setTimeout のラッパー
関数 mySetTimeout( 関数、タイムアウト ) {
    タイムアウト[ n = setTimeout( func, タイムアウト ) ] = {
        開始: new Date().getTime(),
        終了: new Date().getTime() + タイムアウト
        t: タイムアウト
    }
    n を返します。
}

これは、IE 6 以外のブラウザーでも問題なく機能します。元の iPhone でさえ、非同期になると予想していました。

4

13 に答える 13

65

記録のために、node.js の残り時間を取得する方法があります。

var timeout = setTimeout(function() {}, 3600 * 1000);

setInterval(function() {
    console.log('Time left: '+getTimeLeft(timeout)+'s');
}, 2000);

function getTimeLeft(timeout) {
    return Math.ceil((timeout._idleStart + timeout._idleTimeout - Date.now()) / 1000);
}

版画:

$ node test.js 
Time left: 3599s
Time left: 3597s
Time left: 3595s
Time left: 3593s

これはFirefoxでは機能しないようですが、node.jsはjavascriptであるため、ノードソリューションを探している人にはこの発言が役立つかもしれないと思いました.

于 2012-05-28T14:32:52.757 に答える
61

編集:私は実際にもっと良いものを作ったと思います:https://stackoverflow.com/a/36389263/2378102

私はこの関数を作成し、よく使用します。

function timer(callback, delay) {
    var id, started, remaining = delay, running

    this.start = function() {
        running = true
        started = new Date()
        id = setTimeout(callback, remaining)
    }

    this.pause = function() {
        running = false
        clearTimeout(id)
        remaining -= new Date() - started
    }

    this.getTimeLeft = function() {
        if (running) {
            this.pause()
            this.start()
        }

        return remaining
    }

    this.getStateRunning = function() {
        return running
    }

    this.start()
}

タイマーを作る:

a = new timer(function() {
    // What ever
}, 3000)

したがって、残りの時間が必要な場合は、次のようにします。

a.getTimeLeft()
于 2013-12-23T14:40:52.823 に答える
31

ライブラリ コードを変更できない場合は、目的に合わせて setTimeout を再定義する必要があります。これはあなたができることの例です:

(function () {
var nativeSetTimeout = window.setTimeout;

window.bindTimeout = function (listener, interval) {
    function setTimeout(code, delay) {
        var elapsed = 0,
            h;

        h = window.setInterval(function () {
                elapsed += interval;
                if (elapsed < delay) {
                    listener(delay - elapsed);
                } else {
                    window.clearInterval(h);
                }
            }, interval);
        return nativeSetTimeout(code, delay);
    }

    window.setTimeout = setTimeout;
    setTimeout._native = nativeSetTimeout;
};
}());
window.bindTimeout(function (t) {console.log(t + "ms remaining");}, 100);
window.setTimeout(function () {console.log("All done.");}, 1000);

これは製品コードではありませんが、正しい方向に進むはずです。タイムアウトごとにバインドできるリスナーは 1 つだけであることに注意してください。私はこれで大規模なテストを行っていませんが、Firebug で動作します。

より堅牢なソリューションでは、setTimeout をラップする同じ手法を使用しますが、代わりに、返された timeoutId からリスナーへのマップを使用して、タイムアウトごとに複数のリスナーを処理します。タイムアウトがクリアされた場合にリスナーをデタッチできるように、clearTimeout をラップすることも検討してください。

于 2010-06-30T16:57:59.897 に答える
4

Javascript のイベント スタックは、あなたが思うように動作しません。

タイムアウト イベントが作成されると、イベント キューに追加されますが、そのイベントが発生している間は他のイベントが優先され、実行時間が遅延し、ランタイムが延期される場合があります。

例: 画面に何かを警告するために、10 秒の遅延でタイムアウトを作成します。これはイベント スタックに追加され、現在のすべてのイベントが発生した後に実行されます (多少の遅延が発生します)。次に、タイムアウトが処理されると、ブラウザは引き続き他のイベントをキャプチャしてそれらをスタックに追加するため、処理がさらに遅れます。ユーザーがクリックするか、ctrl+typing を何度も行うと、それらのイベントが現在のスタックよりも優先されます。10 秒が 15 秒、またはそれ以上になることもあります。


そうは言っても、経過した時間を偽る方法はたくさんあります。1 つの方法は、setTimeout をスタックに追加した直後に setInterval を実行することです。

例: 10 秒の遅延で settimeout を実行します (その遅延をグローバルに保存します)。次に、毎秒実行される setInterval を実行して、遅延から 1 を減算し、残りの遅延を出力します。イベント スタックが実際の時間にどのように影響するか (前述) のため、これでも正確ではありませんが、カウントは得られます。


つまり、残り時間を取得する実際の方法はありません。ユーザーに見積もりを伝えようとする方法しかありません。

于 2010-06-30T15:27:02.730 に答える
0

誰かがこれを振り返るなら。タイムアウトまたはインターバルの残り時間を取得したり、その他のことを実行したりできる、タイムアウトおよびインターバル マネージャーを作成しました。より気の利いた、より正確にするために追加しますが、そのままでもかなりうまく機能するようです(ただし、さらに正確にするためのアイデアがいくつかあります)。

https://github.com/vhmth/Tock

于 2012-11-03T20:42:30.357 に答える
0

いいえ、ただし、関数内のアニメーション用に独自の setTimeout/setInterval を設定できます。

質問が次のようになっているとします。

function myQuestion() {
  // animate the progress bar for 1 sec
  animate( "progressbar", 1000 );

  // do the question stuff
  // ...
}

そして、アニメーションは次の 2 つの関数によって処理されます。

function interpolate( start, end, pos ) {
  return start + ( pos * (end - start) );
}

function animate( dom, interval, delay ) {

      interval = interval || 1000;
      delay    = delay    || 10;

  var start    = Number(new Date());

  if ( typeof dom === "string" ) {
    dom = document.getElementById( dom );
  }

  function step() {

    var now     = Number(new Date()),
        elapsed = now - start,
        pos     = elapsed / interval,
        value   = ~~interpolate( 0, 500, pos ); // 0-500px (progress bar)

    dom.style.width = value + "px";

    if ( elapsed < interval )
      setTimeout( step, delay );
  }

  setTimeout( step, delay );
}
于 2010-06-29T21:12:11.143 に答える
0

私はこの答えを探してここに立ち寄りましたが、私の問題を考えすぎていました. setTimeout の進行中に時間を追跡する必要があるためにここにいる場合は、別の方法があります。

    var focusTime = parseInt(msg.time) * 1000

    setTimeout(function() {
        alert('Nice Job Heres 5 Schrute bucks')
        clearInterval(timerInterval)
    }, focusTime)

    var timerInterval = setInterval(function(){
        focusTime -= 1000
        initTimer(focusTime / 1000)
    }, 1000);
于 2018-12-22T17:19:20.383 に答える