0
Help us understand the problem. What are the problem?

posted at

node.jsでHIITのTimerを作った

フィヨルドブートキャンプのプラクティスでnpmを自作しました。
せっかくなのでqiitaで公開させてもらおうと思ったので、勇気を出して書かせてもらってます。

「もっとこうした方がいいんじゃない?」などのご意見がありましたらコメントしてもらえると嬉しいです!

どんなnpmを作ったのか

作ったnpmは、最近流行りのトレーニング手法であるHIIT(High Intensity Interval Training)のタイマーです。

話題の筋トレ「HIIT」とは?
HIITとは、「High Intensity Interval Training(高強度インターバルトレーニング)」の略で、負荷の高い運動と小休憩を繰り返すトレーニング法のこと。限界まで体を追い込むことで、常に脂肪が燃焼しやすい状態をキープし、体脂肪減少と筋肉増量効果を得るものです。

実際に作成したnpmはこちらで確認できます↓
- npm:hiit_timer
- GitHub:github.com/R-Tsukada/hiit-timer

実際どんな感じで動くのか

  1. ワークアウト時間の選択

Image from Gyazo

  1. インターバル時間の選択

Image from Gyazo

  1. 1,2を何セット行うかを選択

Image from Gyazo

作成したコード

最終的なコード

const log = require('single-line-log').stdout
const player = require('play-sound')(opts = {})
const { prompt } = require('enquirer')
const emoji = require('node-emoji');

async function hiitTimer(){
  const workoutTimer = await prompt(
    [
      {
        type: 'select',
        name: 'workoutTime',
        message: 'select workout time',
        choices: ['10', '20', '30', '40', '50', '60']
      },
      {
        type: 'select',
        name: 'restTime',
        message: 'select rest time',
        choices: ['10', '20', '30', '40', '50', '60']
      },
      {
        type: 'select',
        name: 'set',
        message: 'select set number?',
        choices: ['1', '2', '3', '4', '5', '7', '8', '9', '10']
      }
    ]
  )
  const workout = workoutTimer.workoutTime
  const rest = workoutTimer.restTime
  const set = workoutTimer.set

  running(set, workout, rest)
}

async function running(setNumber, workout, rest){
  await log('\x1b[32m10 seconds before Workout')
  await firstWorkout(10)
  for (let i = 0; i < setNumber; i++) {
    log(emoji.get('fist') + ` Set${i + 1} Workoout Start ` + emoji.get('fist'))
    await intervalTimer(workout)
    log((emoji.get('relaxed')) + ` Set${i + 1} Break ` + (emoji.get('relaxed')))
    await intervalTimer(rest)
  }
  await log((emoji.get('congratulations')) + ' Workout Finish' + (emoji.get('exclamation')) + 'Good Job' + (emoji.get('exclamation')) + (emoji.get('congratulations')))
}

function intervalTimer(selectWorkout) {
  return new Promise(resolve => {
      setTimeout(() => {
        const startEffect = player.play('start_effect.mp3')
        resolve()
      }, selectWorkout * 1000)
    }
  )
}

function firstWorkout(second) {
  return new Promise(resolve => {
    setTimeout(() => {
      const startEffect = player.play('start_effect.mp3')
      resolve()
    }, second * 1000)
  })
}

hiitTimer()

悩んだ点

今回色々悩んだことが、「ワークアウトとインターバルを設定したセット数を繰り返す」ことでした。

繰り返すということはsetIntervalを使えばいいのでは?と考えて、↓のような考え方をしていました。

console.log('First Workuout Start')
const running = (function(){
  console.log('First Workuout Start')
  let number = 1
  setInterval(function() {
    if (number === 2) {
      console.log('break')
    } else if (number === 3) {
      console.log('Workuout Start')
    }
    number += 1
  }, 1000)
})

async function play(hiitNumber){
  for (let i = 0; i < hiitNumber; i++) {
    running()
}}
play(1)

このコードでも一応実装したい通りの動きになったのですが、、

First Workuout Start
break
Workuout Start

play(3)のようにセット数を複数回繰り返すと、

First Workuout Start
break
break
break
Workuout Start
Workuout Start
Workuout Start

breakWorkuout Startが連続で処理されてしまってインターバルのタイマーになりませんでした。

非同期的に処理されてしまってるので、同期処理になるようにコードを変える必要性があるなと思いました。

修正した点

非同期処理が原因でインターバルタイマーの動きになってないので、同期処理になるようにコードを修正。

そもそもsetIntervalが非同期処理を前提にしたメソッドなので、setIntervalではなく、setTimeoutを繰り返し処理を使うことにしました。

intervalTimerというメソッドを作成して、workout(運動時間)、rest(休憩時間)の時間をそれぞれ引数で渡します。

まずはenquireを使ってworkout, rest, set(セット数)を決めます。

sync function hiitTimer(){

  /* enquireで,workout、rest、setを選択 */
  const workoutTimer = await prompt(
    [
      {
        type: 'select',
        name: 'workoutTime',
        message: 'select workout time',
        choices: ['10', '20', '30', '40', '50', '60']
      },
      {
        type: 'select',
        name: 'restTime',
        message: 'select rest time',
        choices: ['10', '20', '30', '40', '50', '60']
      },
      {
        type: 'select',
        name: 'set',
        message: 'select set number?',
        choices: ['1', '2', '3', '4', '5', '7', '8', '9', '10']
      }
    ]
  )
  const workout = workoutTimer.workoutTime
  const rest = workoutTimer.restTime
  const set = workoutTimer.set

  running(set, workout, rest)
}

enquireで選択したworkout, restsetTimeout に渡す。

function intervalTimer(selectWorkout) {
  return new Promise(resolve => {
      setTimeout(() => {
        const startEffect = player.play('start_effect.mp3')
        resolve()
      }, selectWorkout * 1000)
    }
  )
}

async/await を使って同期処理で実行。

async function running(setNumber, workout, rest){
await log('\x1b[32m10 seconds before Workout')
await firstWorkout(10)
for (let i = 0; i < setNumber; i++) {
log(emoji.get('fist') + ` Set${i + 1} Workoout Start ` + emoji.get('fist'))
await intervalTimer(workout)
log((emoji.get('relaxed')) + ` Set${i + 1} Break ` + (emoji.get('relaxed')))
await intervalTimer(rest)
}
await log((emoji.get('congratulations')) + ' Workout Finish' + (emoji.get('exclamation')) + 'Good Job' + (emoji.get('exclamation')) + (emoji.get('congratulations')))
}

これでHIITのタイマー機能を実装することができました!

改善したい点

最後に改善したい点について書きます。

アドバイス等がありましたらコメントをいただけると嬉しいです!

node_modules/hiit_timerのディレクトリに移動しなければ使えない

作成したnpmはmp3を使用しているので、mp3が入ってるnode_modules/hiit_timerに移動しないと使えないです。。

リファクタリングが不十分

もう少しスッキリしたコードになるんじゃないかと思うのですが、具体的にどうしたらいいのかわからず。。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
0
Help us understand the problem. What are the problem?