どうも、フロントエンドエンジニアのRYOです。
最近、昼食の後にコード書いていると物凄く眠くなってきて気づいたら大量の文字列が入力されていたという怪奇現象が起きることがあります。
食欲の秋(もう終わる)ですが眠くなるほどの食べ過ぎには注意しないといけませんね。
さて、眠くなるといえばsleep。実はプログラムも眠らせることができちゃいます。
ということで今回は良くある事例を交えてJavaScriptでsleep関数を実装してみましょう〜。
Webサイト上でアニメーションを実装する際、この動きはx秒後に実行したいという時ありますよね?
そんな時パッと思いつくのはsetTimeoutを使った非同期処理ですが、処理をコールバック関数として記述しないといけないのでコードが少し読みづらくなってしまいますよね...。
そんな時は!なんと!async/awaitを用いたsleep関数を自作して読みやすいコードにできます!
すごい!!やってみましょう!
比較のためにsetTimeoutのコールバックとasync/awaitでの実装パターンの2種類を見ていきます。
まずはsetTimeoutでのコールバックパターンから実装。
以下、時間差でのアニメーションを想定したコードです。
const animateTime = 5000 // 5秒 const animationFn = () => { animate1() // 何かしらのアニメーション関数 setTimeout(() => { animate2() // 何かしらのアニメーション関数 setTimeout(() => { animate3() // 何かしらのアニメーション関数 }, animateTime) }, animateTime) }
animate1が実行された5秒後にanimate2、さらに5秒後animate3を実行してますね。
...うーん。読みづらくない?これはコールバック地獄に片足突っ込んでますよ。
じゃあ次はasync/awaitのパターンで実装してみましょう。
Promiseとasync/awaitを使いますのでブラウザが指定のESバージョンに対応していないって人はブラウザ変えるか各自バベるようにお願いします。
https://babeljs.io/
const animateTime = 5000 // 5秒 const sleep = (time) => new Promise((resolve) => setTimeout(resolve, time)) const animationFn = async () => { animate1() await sleep(animateTime) // 5秒待機 animate2() await sleep(animateTime) // 5秒待機 animate3() }
Yes!!見やすい!!完全に勝ちです!
コールバックによるネストがなくなってスッキリしました。コードが見やすくなったことで記述ミスも少なくなり、心に平穏が訪れます。
コードの説明をしますと、sleep関数はpromiseを戻り値とする関数です。
関数内部でsetTimeoutを実行しており、指定した秒数後にresolveが実行されることによりpromiseが解決されます。
これをasync/awaitで制御することで待機時間を作っているわけですね。
const sleep = (time: number): Promise<void> => new Promise((resolve) => setTimeout(resolve, time))
もちろんアニメーションに限らず、待機時間が必要な処理の場合は流用できます。promiseベースの実装なのでpromise系のメソッド全般とも相性が良いでしょう。utilsクラスなどを作ってimportで呼び出すなどすると非常に便利です。
今回はasync/awaitを使用したsleep関数の実装方法についてご紹介しました。
とても便利なのでぜひ使ってみてくださいね。あと、食べ過ぎには注意です。眠くなっちゃうので。
弊社MONSTER DIVEではフロントエンドエンジニアを募集しています。
新しいことに挑戦したり、技術を突き詰めていく社内環境が整っていますので多くの学びや経験が得られます。新鮮気鋭の若手エンジニアさんも技術を突き詰めたいエンジニアさんも大歓迎です。興味を持っていただけた方はこちらから募集要項をご覧ください。