2015-12-27 11 views
14

まず、自分のコードの例をJS Fiddleとその下に示します。複数回停止して起動したときにタイマー機能が正しく動作しない

私はパーソナルトレーニングWebアプリケーションに取り組んでいます。基本的にはヒットして、ランダムな順序で一連のタスクを5分間実行します。プログラムはsessionTasks配列を作成し、配列はtasks配列に対してランダムな順序で配置され、5分の制限に適合します。現在、tasksの配列は、4つのタスクとそれぞれのテストで作成したものの1つです。

私が遭遇した問題は、次のとおりです。タスクをクリックすると、次のタスクに進むことができます。次に再生する秒数が速くなります。私が複製を見つけた方法は次のとおりです:

  1. 再生をクリックします。
  2. タスクのテキストをすばやくクリックしてタスクをパワーアップします。
  3. 再生をもう一度クリックします。

ここで、秒はより早く動くはずです。そうでない場合は、今行ったことを繰り返します。それは不規則ですが、通常は2回目の試行で行います。

なぜ私はこのように動作するのか理解できません。私はおそらくそれがすべて#taskTimerを実行するために使用されたタイマーを作成していたと思ったが、それは私には意味をなさない。 Timer機能に問題がありますか?私のコードで何が間違っていますか? Timer.stop()

mainMenu(); 
 

 

 
var totalSessionTasks, taskIterator, selectedTimeInSecs = 300; 
 

 
var taskTimer = new Timer("#taskTimer", nextTask); 
 

 
var globalTimer = new Timer("#globalTimer", function() { 
 

 
}); 
 

 
var tasks = [ 
 
    ["First task", 0, 30], 
 
    ["Second task", 0, 15], 
 
    ["Third task", 0, 10], 
 
    ["Fourth task", 3, 0] 
 
]; 
 

 
var sessionTasks = [ 
 

 
] 
 

 

 

 

 
function setUpSession() { 
 

 
    sessionTasks = [] 
 

 
    if (tasks.length != 0) { 
 

 
    var sessionTasksSeconds = 0; //the seconds of the session being filled 
 
    var sessionTasksSecondsToFill = selectedTimeInSecs; //seconds left in the session to fill 
 
    var newTaskSeconds = 0; //seconds of the next task being added to the session 
 
    var sessionFull = false; 
 

 
    console.log('Session Empty'); 
 

 
    while (sessionFull === false) { 
 

 
     var areThereAnyTaskThatFitInTheSession = 
 
     tasks.some(function(item) { 
 
      return ((item[1] * 60 + item[2]) <= sessionTasksSecondsToFill) && (item != sessionTasks[sessionTasks.length - 1]); 
 
     }); 
 
     console.log(areThereAnyTaskThatFitInTheSession); 
 

 
     if (areThereAnyTaskThatFitInTheSession) { 
 
     do { 
 
      var randTaskNum = Math.floor(Math.random() * tasks.length); 
 
     } while (((tasks[randTaskNum][1] * 60 + tasks[randTaskNum][2]) > sessionTasksSecondsToFill) || (tasks[randTaskNum] == sessionTasks[sessionTasks.length - 1])) 
 

 
     sessionTasks.push(tasks[randTaskNum]); 
 
     newTaskSeconds = (tasks[randTaskNum][1]) * 60 + tasks[randTaskNum][2]; 
 
     sessionTasksSecondsToFill -= newTaskSeconds; 
 
     sessionTasksSeconds += newTaskSeconds; 
 

 
     console.log(tasks[randTaskNum][0] + ": " + newTaskSeconds + "s"); 
 
     console.log(sessionTasksSeconds) 
 

 
     } else if (sessionTasks.length == 0) { 
 
     note("All your tasks are too big for a game of " + selectedTimeInSecs/60 + " minutes!"); 
 
     break; 
 
     } else { 
 
     console.log('Session full'); 
 
     sessionFull = true; 
 
     taskIterator = -1; 
 
     totalSessionTasks = sessionTasks.length; 
 
     console.log(totalSessionTasks); 
 

 
     globalTimer.set(0, sessionTasksSeconds); 
 
     nextTask(); 
 
     globalTimer.run(); 
 
     taskTimer.run(); 
 
     } 
 

 

 
    } 
 

 
    } else { 
 
    note("You don't have have any tasks in your playlists!"); 
 
    } 
 

 
} 
 

 

 
function nextTask() { 
 

 
    if (taskIterator + 1 < totalSessionTasks) { 
 
    taskIterator++; 
 
    $("#taskText").text(sessionTasks[taskIterator][0]); 
 
    globalTimer.subtract(0, taskTimer.getTotalTimeInSeconds()) 
 
    taskTimer.set(sessionTasks[taskIterator][1], sessionTasks[taskIterator][2]); 
 
    $("#taskCounter").text(taskIterator + 1 + " of " + totalSessionTasks + " tasks"); 
 
    } else { 
 
    mainMenu(); 
 
    taskTimer.stop(); 
 
    globalTimer.stop(); 
 
    note("Thanks for playing!"); 
 
    } 
 

 

 
} 
 

 
//timer object function 
 
function Timer(element, callback) { 
 

 
    var ac, minutes, seconds, finalTimeInSeconds, displayMinutes, displaySeconds, interval = 1000, 
 
    self = this, 
 
    timeLeftToNextSecond = 1000; 
 
    this.running = false; 
 

 
    this.set = function(inputMinutes, inputSeconds) { 
 

 
    finalTimeInSeconds = inputMinutes * 60 + inputSeconds; 
 
    minutes = (Math.floor(finalTimeInSeconds/60)); 
 
    seconds = finalTimeInSeconds % 60; 
 

 
    this.print(); 
 
    } 
 

 
    this.add = function(inputMinutes, inputSeconds) { 
 

 
    finalTimeInSeconds += inputMinutes * 60 + inputSeconds; 
 
    finalTimeInSeconds = (finalTimeInSeconds < 0) ? 0 : finalTimeInSeconds; 
 
    minutes = (Math.floor(finalTimeInSeconds/60)); 
 
    seconds = finalTimeInSeconds % 60; 
 

 
    this.print(); 
 
    } 
 

 
    this.subtract = function(inputMinutes, inputSeconds) { 
 

 
    finalTimeInSeconds -= inputMinutes * 60 + inputSeconds; 
 
    if (finalTimeInSeconds <= 0) { 
 
     callback() 
 
    } 
 
    finalTimeInSeconds = (finalTimeInSeconds < 0) ? 0 : finalTimeInSeconds; 
 
    minutes = (Math.floor(finalTimeInSeconds/60)); 
 
    seconds = finalTimeInSeconds % 60; 
 
    this.print(); 
 
    } 
 

 
    this.reset = function() { 
 

 
    this.set(0, 0); 
 
    } 
 

 
    this.print = function() { 
 

 
    displayMinutes = (minutes.toString().length == 1) ? "0" + minutes : minutes; //ternary operator: adds a zero to the beggining 
 
    displaySeconds = (seconds.toString().length == 1) ? "0" + seconds : seconds; //of the number if it has only one caracter. 
 

 
    $(element).text(displayMinutes + ":" + displaySeconds); 
 
    } 
 

 
    this.run = function() { 
 

 
    if (this.running == false) { 
 
     this.running = true; 
 

 
     var _f = function() { 
 
     secondStarted = new Date; 
 
     self.subtract(0, 1); 
 
     interval = 1000; 
 
     } 
 
     ac = setInterval(_f, interval); 
 

 

 
    } 
 
    } 
 

 
    this.stop = function() { 
 

 
    if (this.running == true) { 
 
     this.running = false; 
 
     console.log(this + "(" + element + ") was stopped"); 
 
     stopped = new Date; 
 
     interval = 1000 - (stopped - secondStarted); 
 
     clearInterval(ac); 
 
    } 
 
    } 
 

 
    this.getTotalTimeInSeconds = function() { 
 

 

 
    return finalTimeInSeconds; 
 
    } 
 

 
    this.reset(); 
 

 
} 
 

 
function note(string) { 
 
    alert(string); 
 
} 
 

 
function mainMenu() { 
 
    //EMPTY BODY 
 
    $("body").empty(); 
 
    $("body").append(
 
    //BUTTONS 
 
    "<div id='playButton' class='mainButton'><div class='buttonText mainButtonText'>PLAY</div></div>" 
 
); 
 
    //BINDS 
 
    $("#playButton").bind("click", function(){ 
 
    \t playMain(); 
 
    setUpSession(); 
 
    }); 
 

 
} 
 

 
function playMain() { 
 
    //EMPTY BODY 
 
    $("body").empty(); 
 
    $("body").append(
 
    //TASK TEXT 
 
    "<p class='text' id='taskText'>Lorem ipsum dolor sit amet.</p>", 
 
    //TIMERS 
 
    "<div id='taskTimerWrap'><p class='text timer' id='taskTimer'>00:00</p><p class='text' id='taskTimerText'>Task Time</p></div>", 
 
    "<div id='globalTimerWrap'><p class='text timer' id='globalTimer'>00:00</p><p class='text' id='globalTimerText'>Global Time</p></div>", 
 
    //TASK COUNTER 
 
    "<div class='text' id='taskCounter'>0/0 tasks completed</div>" 
 
); 
 
    //BINDS 
 
    $("#taskText").bind("click", nextTask); 
 
}
#taskText { 
 
    text-align: center; 
 
    display: table; 
 
    vertical-align: middle; 
 
    height: auto; 
 
    width: 100%; 
 
    top: 50px; 
 
    bottom: 0; 
 
    left: 0; 
 
    right: 0; 
 
    position: absolute; 
 
    margin: auto; 
 
    font-size: 65px; 
 
    cursor: pointer; 
 
} 
 

 
#taskTimerWrap { 
 
    text-align: center; 
 
    top: 0; 
 
    right: 0; 
 
    left: 170px; 
 
    margin: 5px; 
 
    position: absolute; 
 
    -webkit-transition: all 0.5s ease; 
 
} 
 

 
.timer { 
 
    font-size: 64px; 
 
    margin: 0; 
 
    line-height: 0.88; 
 
} 
 

 
#taskTimerText { 
 
    font-size: 34.4px; 
 
    margin: 0; 
 
    line-height: 0.65; 
 
} 
 

 
#globalTimerWrap { 
 
    text-align: center; 
 
    top: 0; 
 
    left: 0; 
 
    right: 170px; 
 
    margin: 5px; 
 
    position: absolute; 
 
} 
 

 
#globalTimerText { 
 
    font-size: 28.5px; 
 
    margin: 0; 
 
    line-height: 0.78; 
 
    transform: scale(1, 1.2); 
 
} 
 

 
#taskCounter { 
 
    text-align: center; 
 
    bottom: 0; 
 
    right: 0; 
 
    left: 0; 
 
    width: auto; 
 
    position: absolute; 
 
    font-size: 30px; 
 
    color: #98D8D9; 
 
    -webkit-transition: all 0.5s ease; 
 
} 
 

 
#taskCounter:hover { 
 
    color: #F1F2F0 
 
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

答えて

2

あなたは次の実行のために使われて間隔を変更。 _f()の間隔変数を変更しても、使用する間隔はsetInterval()に変更されません。あなたの代わりにsetTimeout()を使用する必要があります。この場合

:ここ

function Timer(element, callback) {  
    var ac, minutes, seconds, finalTimeInSeconds, displayMinutes, displaySeconds, timeout = 1000, 
    self = this, 
    timeLeftToNextSecond = 1000; 
    this.running = false; 

    /* ... */ 

    this.run = function() { 
    if (this.running == false) { 
     this.running = true; 

     var _f = function() { 
     secondStarted = new Date; 
     self.subtract(0, 1);   
     ac = setTimeout(_f, 1000); 
     } 
     ac = setTimeout(_f, timeout); 
    } 
    } 

    this.stop = function() {  
    if (this.running == true) { 
     this.running = false; 
     console.log(this + "(" + element + ") was stopped"); 
     stopped = new Date; 
     timeout = 1000 - (stopped - secondStarted); 
     clearTimeout(ac); 
    } 
    } 

    /* ... */  
} 
+0

私は次のタスクを取得するタスクのテキストをclic.kingの機能を追加したときに、その行がすでにその行が何@JocaPinto –

+0

のみ問題が起こることを始めたものの、その行が必要とされていますでもやらなければならない?うん、それはタスクをクリックしないと、 'stopped-secondStarted'は常に' 0'になるからです。 –

+0

を存在 –

1

は問題はこの行は、予測不可能な間隔を作成Timer

の変数intervalにあるjsfiddle

での更新ですTimer.stop()

interval = 1000 - (stopped - secondStarted); 

あなたは時間間隔を短くしたい場合、あなたはplay_countプロパティを追加することができます:私が見たよう

... 

    //timer object function 
    function Timer(element, callback) { 

    var ac, minutes, seconds, finalTimeInSeconds, displayMinutes, displaySeconds, interval = 1000, 
    self = this, 
    timeLeftToNextSecond = 1000; 

    this.running = false; 
play_count = 0; // play count property 

... 

    this.run = function() { 

    if (this.running == false) { 
     this.running = true; 

     var _f = function() { 
     secondStarted = new Date; 
     self.subtract(0, 1); 
     interval = Math.max(1000 - play_count * 100, 500); // ** <-- shorten time interval 
     } 
     ac = setInterval(_f, interval); 


    } 
    } 

    this.stop = function() { 

    if (this.running == true) { 
     this.running = false; 
     console.log(this + "(" + element + ") was stopped"); 
//  stopped = new Date; 
//  interval = 1000 - (stopped - secondStarted); 
      play_count++; 
     clearInterval(ac); 
    } 
    } 

    this.getTotalTimeInSeconds = function() { 


    return finalTimeInSeconds; 
    } 

    this.reset(); 

} 
... 
+0

私の答えはあなたの意図に合っていますか? –

+0

彼はJSフィドルを提供しました。そこにあなたの変更を試してみてください。 (私はあなたの変更をフィドルで試しましたが、うまくいきませんでしたので、自分でフィドルを試してみて、働いているときにあなたのフィドルリンクを保存して共有してください) –

1

を、あなたは間隔コールバック関数内から変数intervalに値を設定しようとしています。 setIntervalが実行されたとき

 var _f = function() { 
     secondStarted = new Date; 
     self.subtract(0, 1); 
     //interval = 1000; REMOVE THIS LINE 
     } 
     interval = 1000; //ADD IT HERE 
     ac = setInterval(_f, interval); 

は実際、intervalの値はありません。_fによって更新されていないのは、setInterval()の実行後にその関数が実行されるためです。また、setInterval()が既に存在する値intervalで呼び出された後は、作成した間隔に遅れ時間を設定しているため、後で変更すると作成された間隔に影響はありません。

interval = 1000 - (stopped - secondStarted); //I'm not sure what you are trying to do with this, possibly removing this line will also fix your problem.) 

コンプリートワーキングデモ:

そして、ここではJS Fiddleあり、それからinterval変化の値があるため、このラインの初期値1000年です。

mainMenu(); 
 

 

 
var totalSessionTasks, taskIterator, selectedTimeInSecs = 300; 
 

 
var taskTimer = new Timer("#taskTimer", nextTask); 
 

 
var globalTimer = new Timer("#globalTimer", function() { 
 

 
}); 
 

 
var tasks = [ 
 
    ["First task", 0, 30], 
 
    ["Second task", 0, 15], 
 
    ["Third task", 0, 10], 
 
    ["Fourth task", 3, 0] 
 
]; 
 

 
var sessionTasks = [ 
 

 
] 
 

 

 

 

 
function setUpSession() { 
 

 
    sessionTasks = [] 
 

 
    if (tasks.length != 0) { 
 

 
    var sessionTasksSeconds = 0; //the seconds of the session being filled 
 
    var sessionTasksSecondsToFill = selectedTimeInSecs; //seconds left in the session to fill 
 
    var newTaskSeconds = 0; //seconds of the next task being added to the session 
 
    var sessionFull = false; 
 

 
    console.log('Session Empty'); 
 

 
    while (sessionFull === false) { 
 

 
     var areThereAnyTaskThatFitInTheSession = 
 
     tasks.some(function(item) { 
 
      return ((item[1] * 60 + item[2]) <= sessionTasksSecondsToFill) && (item != sessionTasks[sessionTasks.length - 1]); 
 
     }); 
 
     console.log(areThereAnyTaskThatFitInTheSession); 
 

 
     if (areThereAnyTaskThatFitInTheSession) { 
 
     do { 
 
      var randTaskNum = Math.floor(Math.random() * tasks.length); 
 
     } while (((tasks[randTaskNum][1] * 60 + tasks[randTaskNum][2]) > sessionTasksSecondsToFill) || (tasks[randTaskNum] == sessionTasks[sessionTasks.length - 1])) 
 

 
     sessionTasks.push(tasks[randTaskNum]); 
 
     newTaskSeconds = (tasks[randTaskNum][1]) * 60 + tasks[randTaskNum][2]; 
 
     sessionTasksSecondsToFill -= newTaskSeconds; 
 
     sessionTasksSeconds += newTaskSeconds; 
 

 
     console.log(tasks[randTaskNum][0] + ": " + newTaskSeconds + "s"); 
 
     console.log(sessionTasksSeconds) 
 

 
     } else if (sessionTasks.length == 0) { 
 
     note("All your tasks are too big for a game of " + selectedTimeInSecs/60 + " minutes!"); 
 
     break; 
 
     } else { 
 
     console.log('Session full'); 
 
     sessionFull = true; 
 
     taskIterator = -1; 
 
     totalSessionTasks = sessionTasks.length; 
 
     console.log(totalSessionTasks); 
 

 
     globalTimer.set(0, sessionTasksSeconds); 
 
     nextTask(); 
 
     globalTimer.run(); 
 
     taskTimer.run(); 
 
     } 
 

 

 
    } 
 

 
    } else { 
 
    note("You don't have have any tasks in your playlists!"); 
 
    } 
 

 
} 
 

 

 
function nextTask() { 
 

 
    if (taskIterator + 1 < totalSessionTasks) { 
 
    taskIterator++; 
 
    $("#taskText").text(sessionTasks[taskIterator][0]); 
 
    globalTimer.subtract(0, taskTimer.getTotalTimeInSeconds()) 
 
    taskTimer.set(sessionTasks[taskIterator][1], sessionTasks[taskIterator][2]); 
 
    $("#taskCounter").text(taskIterator + 1 + " of " + totalSessionTasks + " tasks"); 
 
    } else { 
 
    mainMenu(); 
 
    taskTimer.stop(); 
 
    globalTimer.stop(); 
 
    note("Thanks for playing!"); 
 
    } 
 

 

 
} 
 

 
//timer object function 
 
function Timer(element, callback) { 
 

 
    var ac, minutes, seconds, finalTimeInSeconds, displayMinutes, displaySeconds, interval = 1000, 
 
    self = this, 
 
    timeLeftToNextSecond = 1000; 
 
    this.running = false; 
 

 
    this.set = function(inputMinutes, inputSeconds) { 
 

 
    finalTimeInSeconds = inputMinutes * 60 + inputSeconds; 
 
    minutes = (Math.floor(finalTimeInSeconds/60)); 
 
    seconds = finalTimeInSeconds % 60; 
 

 
    this.print(); 
 
    } 
 

 
    this.add = function(inputMinutes, inputSeconds) { 
 

 
    finalTimeInSeconds += inputMinutes * 60 + inputSeconds; 
 
    finalTimeInSeconds = (finalTimeInSeconds < 0) ? 0 : finalTimeInSeconds; 
 
    minutes = (Math.floor(finalTimeInSeconds/60)); 
 
    seconds = finalTimeInSeconds % 60; 
 

 
    this.print(); 
 
    } 
 

 
    this.subtract = function(inputMinutes, inputSeconds) { 
 

 
    finalTimeInSeconds -= inputMinutes * 60 + inputSeconds; 
 
    if (finalTimeInSeconds <= 0) { 
 
     callback() 
 
    } 
 
    finalTimeInSeconds = (finalTimeInSeconds < 0) ? 0 : finalTimeInSeconds; 
 
    minutes = (Math.floor(finalTimeInSeconds/60)); 
 
    seconds = finalTimeInSeconds % 60; 
 
    this.print(); 
 
    } 
 

 
    this.reset = function() { 
 

 
    this.set(0, 0); 
 
    } 
 

 
    this.print = function() { 
 

 
    displayMinutes = (minutes.toString().length == 1) ? "0" + minutes : minutes; //ternary operator: adds a zero to the beggining 
 
    displaySeconds = (seconds.toString().length == 1) ? "0" + seconds : seconds; //of the number if it has only one caracter. 
 

 
    $(element).text(displayMinutes + ":" + displaySeconds); 
 
    } 
 

 
    this.run = function() { 
 

 
    if (this.running == false) { 
 
     this.running = true; 
 

 
     var _f = function() { 
 
     secondStarted = new Date; 
 
     self.subtract(0, 1); 
 
     //interval = 1000; REMOVE THIS LINE 
 
     } 
 
     interval = 1000; //ADD IT HERE 
 
     ac = setInterval(_f, interval); 
 

 

 
    } 
 
    } 
 

 
    this.stop = function() { 
 

 
    if (this.running == true) { 
 
     this.running = false; 
 
     console.log(this + "(" + element + ") was stopped"); 
 
     stopped = new Date; 
 
     interval = 1000 - (stopped - secondStarted); 
 
     clearInterval(ac); 
 
    } 
 
    } 
 

 
    this.getTotalTimeInSeconds = function() { 
 

 

 
    return finalTimeInSeconds; 
 
    } 
 

 
    this.reset(); 
 

 
} 
 

 
function note(string) { 
 
    alert(string); 
 
} 
 

 
function mainMenu() { 
 
    //EMPTY BODY 
 
    $("body").empty(); 
 
    $("body").append(
 
    //BUTTONS 
 
    "<div id='playButton' class='mainButton'><div class='buttonText mainButtonText'>PLAY</div></div>" 
 
); 
 
    //BINDS 
 
    $("#playButton").bind("click", function(){ 
 
    \t playMain(); 
 
    setUpSession(); 
 
    }); 
 

 
} 
 

 
function playMain() { 
 
    //EMPTY BODY 
 
    $("body").empty(); 
 
    $("body").append(
 
    //TASK TEXT 
 
    "<p class='text' id='taskText'>Lorem ipsum dolor sit amet.</p>", 
 
    //TIMERS 
 
    "<div id='taskTimerWrap'><p class='text timer' id='taskTimer'>00:00</p><p class='text' id='taskTimerText'>Task Time</p></div>", 
 
    "<div id='globalTimerWrap'><p class='text timer' id='globalTimer'>00:00</p><p class='text' id='globalTimerText'>Global Time</p></div>", 
 
    //TASK COUNTER 
 
    "<div class='text' id='taskCounter'>0/0 tasks completed</div>" 
 
); 
 
    //BINDS 
 
    $("#taskText").bind("click", nextTask); 
 
}
#taskText { 
 
    text-align: center; 
 
    display: table; 
 
    vertical-align: middle; 
 
    height: auto; 
 
    width: 100%; 
 
    top: 50px; 
 
    bottom: 0; 
 
    left: 0; 
 
    right: 0; 
 
    position: absolute; 
 
    margin: auto; 
 
    font-size: 65px; 
 
    cursor: pointer; 
 
} 
 

 
#taskTimerWrap { 
 
    text-align: center; 
 
    top: 0; 
 
    right: 0; 
 
    left: 170px; 
 
    margin: 5px; 
 
    position: absolute; 
 
    -webkit-transition: all 0.5s ease; 
 
} 
 

 
.timer { 
 
    font-size: 64px; 
 
    margin: 0; 
 
    line-height: 0.88; 
 
} 
 

 
#taskTimerText { 
 
    font-size: 34.4px; 
 
    margin: 0; 
 
    line-height: 0.65; 
 
} 
 

 
#globalTimerWrap { 
 
    text-align: center; 
 
    top: 0; 
 
    left: 0; 
 
    right: 170px; 
 
    margin: 5px; 
 
    position: absolute; 
 
} 
 

 
#globalTimerText { 
 
    font-size: 28.5px; 
 
    margin: 0; 
 
    line-height: 0.78; 
 
    transform: scale(1, 1.2); 
 
} 
 

 
#taskCounter { 
 
    text-align: center; 
 
    bottom: 0; 
 
    right: 0; 
 
    left: 0; 
 
    width: auto; 
 
    position: absolute; 
 
    font-size: 30px; 
 
    color: #98D8D9; 
 
    -webkit-transition: all 0.5s ease; 
 
} 
 

 
#taskCounter:hover { 
 
    color: #F1F2F0 
 
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

関連する問題