クモのようにコツコツと

フロントエンドエンジニア イイダリョウの技術ブログ。略称「クモコツ」

【JS】setTimeout()とsetInterval()の違い(一回と複数回)

ネイティブJSいろいろやってみたシリーズの続きです。以前、setTimeout()を使って令和カウントダウンタイマーという記事を作りました。これと良く似たメソッドでsetInterval()があるので、2つの違いを体験したく、記事にしました。それでは行きましょう!

【目次】

※参考:【JS】DateとsetTimeout()で作るカウントダウンタイマー(令和まであと何日?) - クモのようにコツコツと

ネイティブJSいろいろやってみたシリーズ
qiita.com

setTimeout()とsetInterval()の書式はほぼ同じ

時間差で処理を実行するsetTimeout()setInterval()。「タイマー処理」と言われる。二つの書式はほとんど同じ。

// 一定時間の後に1回処理を実行
setTimeout(処理, 時間);

// 一定時間ごとに複数回処理を実行
setInterval(処理, 時間);

どちらも第一引数に処理内容、第二引数に時間を書く。

違いは処理の実行回数

  • setTimeout()は第二引数の時間が経った後に1回処理を実行する
  • setInterval()は第二引数の時間ごとに複数回処理を実行する

以前作った令和カウントダウンタイマーはsetTimeout()で書いている。

See the Pen reiwa countdown5 by イイダリョウ (@i_ryo) on CodePen.

1秒ごとにカウントが動く。(もはやカウントダウンがマイナスまで行ってしまっているがw)

※参考:【JS】DateとsetTimeout()で作るカウントダウンタイマー(令和まであと何日?) - クモのようにコツコツと

本来setTimeout()は1回しか処理実行されないはずなのに何故カウントをし続けているのか?

setTimeout()setInterval()は書き方によって挙動が変わる。いくつかの書き方を試してみる。

処理全体をメソッドで囲う

まず処理全体をメソッドで囲ってみる。

setTimeout()

最初にsetTimeout()の例

See the Pen setTimeout-1 by イイダリョウ (@i_ryo) on CodePen.

「Run pen」を押すと画面上の「羊は0匹…」の文字が1秒後に「羊は1匹…」になる。しかしそれ以上は数えない。

HTMLはシンプル

HTMLコード

<section>
    <h1>羊は何匹?</h1>
    <p class="timer">「羊が0匹…」</p>
</section>

. timerのpタグの中に初期は「羊が0匹…」と書いている。ここをJSで変更する。

JSコード

const timer = document.querySelector('.timer');

let counter = 0;

setTimeout(() => {
    if(counter < 100){
            counter++;
         }
    timer.innerHTML = '「羊が' + counter + '匹…」';
}, 1000);
  • 変数timer. timerのDOMを取得
  • 変数counterに初期値0を入れる
  • setTimeout()の第一引数は無名関数
  • 無名関数の中:もしcounter100より少なければ
    counterの値を1追加せよ
    timerの中身をinnerHTMLで「羊が(カウント数)匹…」にする
  • setTimeout()の第二引数は1000ミリ秒(=1秒)

if文で最大100までカウントする条件にしているものの、setTimeout()は1回しか実行されないため、1秒後に「一匹」になるのみ。

setInterval()

上記のコードをsetInterval()にしてみる。

See the Pen setInterval-1 by イイダリョウ (@i_ryo) on CodePen.

「Run pen」を押すと、今度は羊を数え続けている。

JSコード

const timer = document.querySelector('.timer');

let counter = 0;

setInterval(() => {
    if(counter < 100){
            counter++;
         }
    timer.innerHTML = '「羊が' + counter + '匹…」';
}, 1000);

setTimeout()setInterval()に変えただけ。

これによって100匹まで羊を数え続ける!

外部に書いた関数を読み込む

処理全体をメソッドで囲う方法だと処理が増えた時に見通しが悪くなる。処理を外部の関数に書いて、読み込んでみる。

setTimeout()

まずsetTimeout()の例

See the Pen setTimeout-2 by イイダリョウ (@i_ryo) on CodePen.

動きは変わらない。羊を一匹しか数えない。

JSコード

const timer = document.querySelector('.timer');

let counter = 0;

const hitsuji = () => {
    if(counter < 100){
            counter++;
         }
    timer.innerHTML = '「羊が' + counter + '匹…」';
}

setTimeout(hitsuji, 1000);
  • 変数hitsujiの中に無名関数で処理を書く
  • setTimeout()の第一引数で関数hitsujiを読み込む

setTimeout()の見通しは良くなった。第一引数の関数名に括弧がないのはaddEventListener()などと一緒で、関数を即座に実行させないため。

第1引数にイベントタイプ、第2引数に実行される関数(コールバック関数)を指定しています。
上記例ではloadイベントが検知されると同時にコールバック関数が実行されるので、funcに()はつけません。
もし第2引数をfunc()のように括弧をつけて書いてしまうと、JavaScriptが読み込まれた時点でfunc関数が実行されてしまいます。
(loadよりも早いタイミングで関数が実行される。)

※参考:JavaScriptのイベント指定 〜括弧()をつける?つけない?〜 - Qiita

setInterval()

次に、setInterval()もやってみる。

See the Pen setInterval-2 by イイダリョウ (@i_ryo) on CodePen.

こちらも挙動は変わらない!

JSコード

const timer = document.querySelector('.timer');

let counter = 0;

const hitsuji = () => {
    if(counter < 100){
        counter++;
    }
    timer.innerHTML = '「羊が' + counter + '匹…」';
}

setInterval(hitsuji, 1000);

最後の行のsetTimeout()setInterval()にしたのみ。

関数の中にメソッドを書く

次は関数の中にメソッドを書く。少し特殊な書き方になる。(最初の令和カウンターはこの方法を使っている)

setTimeout()

まずsetTimeout()から。

See the Pen setTimeout-3 by イイダリョウ (@i_ryo) on CodePen.

「Run Pen」を押すと、なんと!setInterval()のように繰り返し羊を数え始めた!

const timer = document.querySelector('.timer');

let counter = 0;

const hitsuji = () => {
    if(counter < 100){
        counter++;
    }
    timer.innerHTML = '「羊が' + counter + '匹…」';
    setTimeout(hitsuji, 1000);
}

hitsuji();
  • 変数hitsujiの無名関数の中にsetTimeout()を書く
  • setTimeout()の第一引数に関数自身hitsujiを書く
  • 関数hitsuji()を実行

関数hitsuji()を定義する処理の中にsetTimeout()を書くが、その第一引数の中に自分自身であるhitsujiを書いているのが特殊。

setInterval()

では、これをsetInterval()にしたらどうなるのか?

See the Pen setInterval-3 by イイダリョウ (@i_ryo) on CodePen.

おお、「1匹」「2匹」「4匹」「8匹」「16匹」…とバイバインのように倍数で増え続ける。あっという間に100匹になった!

JSコード

const timer = document.querySelector('.timer');

let counter = 0;

const hitsuji = () => {
    if(counter < 100){
        counter++;
    }
    timer.innerHTML = '「羊が' + counter + '匹…」';
    setInterval(hitsuji, 1000);
}

hitsuji();

ソースをsetTimeout ()setInterval()にしたのみ。

これによって1秒ごとに繰り返す、という処理を1秒ごとに新たに開始するわけだ!

最後に

まとめます。

  • setTimeout()setInterval()とも第一引数は処理、第二引数は時間
  • setTimeout()は一定時間後に一回処理を実行
  • setInterval()は一定時間ごとに複数回処理を実行
  • 処理を外部の関数に書いて読み込むことができる。その場合、カッコは付けない
  • 処理の関数の中にsetTimeout()を書くとsetInterval()のように繰り返し実行される
  • 処理の関数の中にsetInterval()を書くと倍数で増えるので注意!

時間差で発火させたいこともあれば、繰り返し実行したいこともあるので、どちらも重要なメソッドと思います。

最後の処理の中にメソッドを書く方法は、一回か複数回かが直感的ではないかもしれない。この方法にしたほうがいい局面がどんな時なのかまだちゃんとわかっていない。色々な書き方があることは知っておいていいと思いました。

それではまた!


ネイティブJSいろいろやってみたシリーズ
qiita.com