LoginSignup
6
7

More than 5 years have passed since last update.

Javascript初心者がsetTimeoutを使ったとき行き詰ったこと

Last updated at Posted at 2017-10-04

Javascriptの練習にブラウザで動く簡単なゲームを作ろうとしていたところ
setTimeoutを続けて使うとうまく動作しないというところで詰まったのでその解決策

Javascriptは非同期処理を行っています。

まず'#1'を出力しそのあと'#2'を出力したい場合、

setTimeout(() => {
 console.log('#1');
}, 500);
console.log('#2');

こう書くと実行した結果は

 #2
 #1

となってしまいます。

時間のかかる処理がある場合、同期処理の場合はまずその処理を待ってから次の行が実行されますが
非同期処理のJavascriptの場合すぐに次の行のコードが実行されてしまうためです。

これを解決するために、
まずコールバック関数を使う方法です

setTimeout(() => {
  console.log('#1');
  setTimeout(() => {
   console.log('#2');
   setTimeout(() => {
    console.log('#3');
   }, 500);
   }, 500);
}, 500);

この場合、数が多くなるとコールバック関数地獄になりコードの見た目がカオスなことになってしまいます。

そこでPromiseオブジェクトを使うと大分すっきりします。

var p = new Promise((resolve) => {
  setTimeout(() => {
    resolve(console.log('#1'));
  }, 500);
});

p
.then((resolve) => {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(console.log('#2'));
    }, 500);
  })
})
.then((resolve) => {
  setTimeout(() => {
    console.log('#3');
  }, 500);
})

少しややこしいですが処理を順番にthenに渡してやるイメージです。

いろいろな書き方があるので

new Promise((resolve) => {
  setTimeout(() => {
    resolve(console.log('#1'));
  }, 500);
})
.then((resolve) => {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(console.log('#2'));
    }, 500);
  })
})
.then((resolve) => {
  setTimeout(() => {
    console.log('#3');
  }, 500);
})

このようにすべてつなげて書いたり

function p() {
 return new Promise((resolve) => {
   setTimeout(() => {
     resolve(console.log('#1'));
   }, 500);
 });
}

p()
.then((resolve) => {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(console.log('#2'));
    }, 500);
  })
})
.then((resolve) => {
  setTimeout(() => {
    console.log('#3');
  }, 500);
})

関数を使っても動きます。

また、

new Promise((resolve) =>{
  setTimeout(resolve, 500);
})
.then(() =>{return new Promise((resolve) => {
  console.log('#1');
  setTimeout(resolve, 500);
})})
.then(() =>{return new Promise((resolve) => {
  console.log('#2');
  setTimeout(resolve, 500);
})})
.then(() =>{console.log('#3');});

このようにresolve()を使わずに書くこともできます。

Promiseオブジェクトの仕組みはややこしい部分もあるので詳細に解説しているページを見てもらった方がいいと思います。

ちなみに

function() {};

はアロー関数を使って

() =>{};

と短く書くことができます。

以上、Javascript初心者が最近気づいたことのメモでした。

追記

const wait = (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds));

Promise.resolve()
.then( () => wait(500)         )
.then( () => console.log('#1') )
.then( () => wait(500)         )
.then( () => console.log('#2') )
.then( () => wait(500)         )
.then( () => console.log('#3') );

コメントのculageさんのコードが分かりやすかったため追記しました!

6
7
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
7