我刚开始使用JavaScript,并且试图编写一个用于指板训练的小型开源应用程序。我嵌套了一些时间循环以说明hangtime和break之间的间隔:
<html>
<body>
Sets: <input type="number" id="setsIN" value="5">
<br>
Rounds: <input type="number" id="roundsIN" value="6">
<br>
Workout: <input type="number" id="hangIN" value="7">
<br>
Short Break: <input type="number" id="shortbreakIN" value="3">
<br>
Long Break: <input type="number" id="longbreakIN" value="180">
<br>
<hr>
<script>
// Import values
var setsNUMBER = parseInt(document.getElementById("setsIN").value);
var roundsNUMBER = parseInt(document.getElementById("roundsIN").value);
var hangTIME = parseInt(document.getElementById("hangIN").value);
var shortbreakTIME = parseInt(document.getElementById("shortbreakIN").value);
var longbreakTIME = parseInt(document.getElementById("longbreakIN").value);
console.log("Sets: " + setsNUMBER)
console.log("Rounds: " + roundsNUMBER)
console.log("Hang: " + hangTIME)
console.log("Short breaks: " + shortbreakTIME)
console.log("Long breaks: " + longbreakTIME)
// calculate duration
var duration = ((hangTIME + shortbreakTIME) * roundsNUMBER + longbreakTIME) * setsNUMBER
console.log("Duration (minutes): " + duration/60)
// Counter
var setsCOUNT = 1; // Start counting at 1
var roundsCOUNT = 1; // Start counting at 1
var hangCOUNT = 1; // Start counting at 1
var shortbreakCOUNT = 1; // Start counting at 1
var longbreakCOUNT = 1; // Start counting at 1
/////////////////////////////////////////////////////////////////
// Sets
while (setsCOUNT < setsNUMBER+1) {
console.log("Set: "+ setsCOUNT)
setsCOUNT++;
roundsCOUNT = 1;
longbreakCOUNT = 1;
// Rounds
while (roundsCOUNT < roundsNUMBER+1) {
console.log("Round: "+ roundsCOUNT)
roundsCOUNT++;
hangCOUNT = 1;
shortbreakCOUNT = 1;
// HAngtime
while (hangCOUNT < hangTIME+1) {
console.log("WorkOutTime: "+ hangCOUNT)
hangCOUNT++;
}
// Pausetime
while (shortbreakCOUNT < shortbreakTIME+1) {
console.log("ShortBreak: "+ shortbreakCOUNT)
shortbreakCOUNT++;
}
}
// LongBreak
while (longbreakCOUNT < longbreakTIME+1) {
//console.log("longBreak: "+ longbreakCOUNT)
longbreakCOUNT++;
}
}
</script>
</html>
培训的顺序如下:
-7秒锻炼
-休息3秒
重复以上六次(= 60秒)
休息180秒
重复以上五次的所有步骤(= 5 * 4分钟)
看来我正确地输出了序列。
console.log()
以正确的顺序返回。但是,当前,每当我运行脚本时,加载页面后立即返回所有日志行。如何每秒打印一行?我尝试了setTimeout()
,但无法运行。
最佳答案
循环不应该用来组织时间。循环是一系列操作迅速发生的一系列操作。
我要做的是使用一些时间函数:setTimeout
*或requestAnimationFrame
,尽管在后者中,您必须自己跟踪每个帧中的时间。可行并且可能更可靠*,但是出于示例的原因,我使用了setTimeout
。无论如何,这是概念的证明。
您想要做的是:
开始设置,然后致电“开始”或“结束”
开始一轮,然后致电开始锻炼或开始下一组
重复6次:
锻炼身体,然后在7秒后致电短暂休息或长时间休息
休息片刻,然后3秒钟后致电锻炼
稍事休息,然后在180秒后致电“开始设置”
这是一系列步骤,需要x倍的时间(新设置和新回合除外,它们只是数据更新),之间有一定的暂停时间。
码
不要空手而归,这是概念的有效证明:
<html>
<body>
Sets: <input type="number" id="setsIN" value="5">
<br>
Rounds: <input type="number" id="roundsIN" value="6">
<br>
Workout: <input type="number" id="hangIN" value="7">
<br>
Short Break: <input type="number" id="shortbreakIN" value="3">
<br>
Long Break: <input type="number" id="longbreakIN" value="180">
<br>
<hr>
<script>
const setsNUMBER = 'setsNUMBER';
const roundsNUMBER = 'roundsNUMBER';
const hangNUMBER = 'hangNUMBER';
const hangTIME = 'hangTIME';
const shortbreakTIME = 'shortbreakTIME';
const longbreakTIME = 'longbreakTIME';
const setsCOUNT = 'setsCOUNT';
const roundsCOUNT = 'roundsCOUNT';
const hangCOUNT = 'hangCOUNT';
const shortbreakCOUNT = 'shortbreakCOUNT';
const longbreakCOUNT = 'longbreakCOUNT';
function training({ config, data, next: current }) {
switch (current) {
case setsCOUNT: {
if (data[setsCOUNT] < config[setsNUMBER]) {
const updatedSetsCOUNT = data[setsCOUNT] + 1;
console.log(`Set: ${updatedSetsCOUNT}`);
training({
config,
data: {
...data,
[setsCOUNT]: updatedSetsCOUNT,
[roundsCOUNT]: 0,
},
next: roundsCOUNT,
});
} else {
console.log('The end. It was a good workout, bro!');
}
break;
}
case roundsCOUNT: {
if (data.roundsCOUNT < config.roundsNUMBER) {
const updatedRoundsCOUNT = data.roundsCOUNT + 1;
console.log(`Round: ${updatedRoundsCOUNT}`);
training({
config,
data: {
...data,
[roundsCOUNT]: updatedRoundsCOUNT,
[hangCOUNT]: 0,
[shortbreakCOUNT]: 0,
},
next: hangCOUNT,
});
} else {
console.log('New set');
training({
config,
data: {
...data,
roundsCOUNT: 0,
},
next: setsCOUNT,
});
}
break;
}
case hangCOUNT: {
if (data[hangCOUNT] < config[hangNUMBER]) {
const updatedHangCOUNT = data[hangCOUNT] + 1;
console.log(`WorkOutTime: ${updatedHangCOUNT}`);
setTimeout(training, config[hangTIME] * 1000, {
config,
data: {
...data,
[hangCOUNT]: updatedHangCOUNT,
},
next: shortbreakTIME,
});
} else {
training({
config,
data,
next: longbreakCOUNT,
});
}
break;
}
case shortbreakTIME: {
const updatedShortBreakCOUNT = data[shortbreakCOUNT] + 1;
console.log(`Short break: ${updatedShortBreakCOUNT}`);
setTimeout(training, config[shortbreakTIME] * 1000, {
config,
data: {
...data,
[shortbreakCOUNT]: updatedShortBreakCOUNT,
},
next: hangCOUNT,
});
break;
}
case longbreakCOUNT: {
// this update is probably obsolete as setsCOUNT stage is keeping track
const updatedLongbreakCOUNT = data[longbreakCOUNT] + 1;
console.log(`LongBreak: ${updatedLongbreakCOUNT}`);
setTimeout(training, config[longbreakTIME] * 1000, {
config,
data: {
...data,
[longbreakCOUNT]: updatedLongbreakCOUNT,
},
next: roundsCOUNT,
});
break;
}
}
}
const config = {
[setsNUMBER]: parseInt(document.getElementById("setsIN").value),
[roundsNUMBER]: parseInt(document.getElementById("roundsIN").value),
[hangNUMBER]: 6,
[hangTIME]: parseInt(document.getElementById("hangIN").value),
[shortbreakTIME]: parseInt(document.getElementById("shortbreakIN").value),
[longbreakTIME]: parseInt(document.getElementById("longbreakIN").value),
};
console.log("Sets: " + config.setsNUMBER);
console.log("Rounds: " + config.roundsNUMBER);
console.log("Workout time: " + config.hangTIME);
console.log("Short break time: " + config.shortbreakTIME);
console.log("Long break time: " + config.longbreakTIME);
console.log("Duration (minutes): " + (
(
(
(config.hangTIME + config.shortbreakTIME)
* config.roundsNUMBER
+ config.longbreakTIME
)
* config.setsNUMBER
)
/ 60)
);
const data = {
[setsCOUNT]: 0,
[roundsCOUNT]: 0,
[hangCOUNT]: 0,
[shortbreakCOUNT]: 0,
[longbreakCOUNT]: 0,
};
training({ config, data, next: setsCOUNT });
</script>
</body>
</html>
一般概念是函数
training
,该函数接受带有配置,数据和下一步的任意对象,并再次使用新值调用自身,直到满足条件(在这种情况下,完成的集数)。我建议不要按交付使用它。
我会将其拆分为一些小功能。
如果在短暂的休息之后出现了短暂的休息,那么可能会跳过这种短暂的休息。
上面的函数有时会变异对象。这不太可能引起问题,但通过时创建新对象可能会更安全。由你决定。
[编辑]工作演示:https://jsfiddle.net/hmcwf0p5/1/
[编辑]代码2
然后,有人问我上面的代码是否可以显示秒数。 (这是一个很好的示例,为什么从一开始就应该弄清楚规格;否则,可能会导致非常不同的实现。)
简而言之,没有。
长话短说,由于
setTimeout
的性质,我们可以做到这一点并不准确。我什至不想去。因此,我开始思考不同的方法,并提出了时间表。代码:时间轴
想法:运行定时功能,在给定间隔内执行某些操作。在我们的情况下,这将是1秒。然后,根据我们的数据,我们应该做一些事情。
const prepareTimeline = (possibleTimeline) => {
const sortedFrames = Object.keys(possibleTimeline)
.map(Number)
.filter((number) => !Number.isNaN(number))
.sort((a, b) => a - b);
return Object.assign(
sortedFrames.reduce(
(acc, number) => Object.assign(acc, { [number]: possibleTimeline[number] }),
{}
),
{ last: Math.max(...sortedFrames) + 1 }
);
}
const handleFrame = (data) => {
const { second, frames, frames: { last }, timelineId } = data;
if (second == last) {
return clearInterval(timelineId);
}
if (frames[second]) {
frames[second].forEach((message) => {
console.log(message);
});
}
data.second = second + 1;
};
const runTimeline = (frames) => {
const timelineObject = {
second: 0,
frames: prepareTimeline(frames),
timelineId: null,
}
const timelineId = setInterval(handleFrame, 1000, timelineObject);
timelineObject.timelineId = timelineId;
}
怎么了:
runTimeline
拍摄带有框架的对象。关键是发生某事的秒数,值是要显示消息的数组。在
prepareTimeline
函数内部,删除了所有非数字键(作为frames
属性传递),并添加了last
,这是最大值加上1秒,因此我们可以杀死setInterval
。handleFrame
是每秒调用的函数。作为参数,它使用timelineId
(可以传递给clearInterval
的对象),frames
,second
作为对象。在此函数内部,我们对该对象进行了突变。在这里,您可以决定要对框架做什么。您可以使用应用程序的setState或任何您认为合适的状态来代替console.logging它。
另外,在我的示例中,它是数组的对象,但要取决于
handleFrame
接受什么。符号
setInterval(functionName, time, ...params)
将每秒调用一次functionName(...params)
。现在,运行它:
runTimeline({
1: ['Initial message'],
5: ['Second message', 'And last'],
});
在控制台日志中,1秒后首先显示消息
Initial message
然后4秒钟后(同时):
Second message
And last
锻炼时间表
所以剩下的就是建立锻炼框架。
buildWorkoutTimeline
接受参数并运行许多嵌套循环(这在某种程度上是最初的实现)。可能的书写方式可能有所不同,但我会留给您。const buildWorkoutTimeline = ({
sets = 3,
rounds = 5,
workouts = 6,
workoutTime = 7,
pauseTime = 3,
restTime = 180,
} = {}) => {
let seconds = 0;
const workoutTimeline = { [seconds]: [] };
for (let set = 1; set <= sets; set++) {
workoutTimeline[seconds].push(`New set: ${set}`);
for (let round = 1; round <= rounds; round++) {
workoutTimeline[seconds].push(`Set ${set}’s new round: ${round}`);
for (let workout = 1; workout <= workouts; workout++) {
seconds += 1;
workoutTimeline[seconds] = [`Set ${set}, round ${round}’s new workout: ${workout}`];
for (let time = 0; time < workoutTime; time++) {
seconds += 1;
workoutTimeline[seconds] = [`Seconds: ${workoutTime - time}`];
}
if (workout < workouts) {
seconds += 1;
workoutTimeline[seconds] = ['Short break'];
for (let time = 0; time < pauseTime; time++) {
seconds += 1;
workoutTimeline[seconds] = [`Seconds: ${pauseTime - time}`];
}
} else if (round < rounds) {
seconds += 1;
workoutTimeline[seconds] = ['Long break'];
for (let time = 0; time < restTime; time++) {
seconds += 1;
workoutTimeline[seconds] = [`Seconds: ${restTime - time}`];
}
}
}
}
}
seconds += 1;
workoutTimeline[seconds] = [
'Workout finished',
`Total time: ${(seconds / 60) | 0} minutes, ${seconds % 60} seconds`
];
return workoutTimeline;
};
runTimeline(buildWorkoutTimeline());
塔丹
*
setTimeout(someFunction, 1000)
从被调用的那一刻起不会执行1000毫秒,但不能早于1000毫秒。因此,总锻炼时间可能会稍长一些。 requestAnimationFrame
可能会产生更好的结果。测试一下。
关于javascript - 嵌套循环输出的时间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57100868/