ワイ「なに！？ジェネレーター関数を使えば複雑なCSSアニメーションも簡単やと！？」

## 業務中ワイ

ワイ「お、また**株式会社ブラック**はんからお仕事依頼のメールが来てるで」
ワイ「どれどれ・・・」

> 暗井「お世話になっております。株式会社ブラックの暗井 暗人（くらい・あんと）です」
> 暗井「クリックすると**フワフワっと**だんだん縦横に大きくなるボックスを作ってください」
> 暗井「予算は800万円です」

ワイ「これまた何ちゅう**フワフワっと**した指示や」
ワイ「でも**jQuery**の**`animate`**メソッド使えば余裕やろ」

> ワイ「かしこまりました」
> ワイ「何とか800万円以内に抑えます」

ワイ「送信っと」
ワイ「お、早速お返事や」

> 暗井「なお、発注元の都合で**jQueryの使用はできません**」

ワイ「**ファッ！？**」
ワイ「まじか・・・**jQuery禁止**か」
ワイ「800万円で出来るかな・・・」

社長「（それは出来るやろ・・・何年かける気や・・・）」

## ザコーダーワイ、jQuery禁止で困る

ワイ「jQueryなしか・・・」
ワイ「jQueryの`animate`みたいなこと、素のJSとCSSだけで出来んのかな・・・」

ハスケル子「**できますよ**」
ハスケル子「今回の仕様なら**ジェネレーター関数**なんて良いんじゃないですか」

ワイ「何やっけそれ」

## ジェネレーター関数とは

ハスケル子「ジェネレーター関数っていうのは」
ハスケル子「実行すると、**ジェネレーター**を返す関数です」

ワイ「その**ジェネレーター**が分からんわ」

ハスケル子「ジェネレーターは、ある種の**イテレーター**です」

ワイ「今度はその**イテレーター**が分からん。。。」

ハスケル子「・・・」
ハスケル子「簡単にいうと、関数の途中で**一旦止まれる**んです」
ハスケル子「具体的には`yield`って書くと、そこで関数の処理が一旦止まります」

## やってみよう
ハスケル子「じゃあ実際やってみますね」

```js

function* geneFunc () {
  console.log("1回目");
  yield;

  console.log("2回目");
  yield;

  console.log("3回目");
  yield;

  console.log("4回目");
  yield;

  console.log("最後");
}
```

ハスケル子「↑こんな感じで`function`に`*`をつけると**ジェネレーター関数**になります」
ハスケル子「`yield`が来るたびに処理が一旦止まって**関数の外の世界**に出るので」
ハスケル子「この関数は合計5回に分けて実行することができるんです。」

ワイ「ほえ〜」

ハスケル子「まず、`geneFunc`を実行して、戻り値である**ジェネレーター**を受け取ります」

```js
const generator = geneFunc();
```

ワイ「この時点で`console.log("1回目");`が実行される感じ？」

ハスケル子「いえ、まだです」
ハスケル子「`geneFunc`を実行した時点では、関数の中の処理は**何も実行されません**」

ハスケル子「↓こうすると`console.log("1回目");`が実行されます」

```js
generator.next();
```

ワイ「なるほどな」
ワイ「`generator`の持ってる`next`メソッドを実行すると」
ワイ「`yield`の所まで実行して、一旦止まってくれんねやな」

ハスケル子「はい」
ハスケル子「一旦止まって、関数の外で何か処理をして」
ハスケル子「また`generator.next()`で関数の中に戻ったりできるわけです」

ワイ「おお〜、ほな今回の例やと`generator.next()`を5回実行すると」
ワイ「`geneFunc`の中の処理を全部やり切ってくれるわけやね」

ハスケル子「そうです」
ハスケル子「慣れないうちはちょっと、いつどこで何をやってるのか分かりにくいかもしれませんけど」
ハスケル子「処理の順番とかタイミングを自在にコントロールできる強力な機能です」

ハスケル子「非同期処理と組み合わせて使うこともできて」
ハスケル子「[**redux-saga**](https://github.com/redux-saga/redux-saga/blob/master/README_ja.md)なんかは」

> ワイらは`async/await`やなくて**ジェネレーター関数**を使っていくんや！

ハスケル子「って表明してたりします」

ワイ「おお〜・・・」

## そんで、どうやってフワフワっとさせんの？

ワイ「そんでハスケル子ちゃん」
ワイ「クリックすると**フワフワっと**だんだん縦横に大きくなるボックス・・・」
ワイ「これとジェネレータ、関係あるん・・・？」

ハスケル子「大ありです」
ハスケル子「ジェネレータ関数を使うとだいぶスッキリ書けますよ」
ハスケル子「まずは・・・」

```js
const box = document.querySelector(".box");
```

ハスケル子「↑大きさを操作する対象となるDOM要素を取得します」
ハスケル子「そして・・・」

```js
function* fuwafuwa () {
  let boxHeight = 30; // デフォルトの高さは30px
  let boxWidth = 30; // デフォルトの横幅は30px
    
  boxHeight += 30;
  box.style.height = boxHeight + "px"
  // boxを30px高くする
  yield;
  // 一旦止まる

  boxWidth += 30;
  box.style.width = boxWidth + "px"
  // boxを30px横長にする
  yield;
  // 一旦止まる
}
```

ハスケル子「↑`fuwafuwa`っていう**ジェネレータ関数**を定義します」
ハスケル子「この関数の中の処理は・・・」

ワイ「`box`を`30px`高くして`yield`で止まる」
ワイ「`box`を`30px`横長にして`yield`で止まる」
ワイ「って感じやね」

ハスケル子「そうです」
ハスケル子「この処理を関数の中にいっぱい書きます」

ワイ「なるほど！」
ワイ「↓こんな感じやな・・・！」

```js
  boxHeight += 30;
  box.style.height = boxHeight + "px"
  // boxを30px高くする
  yield;
  // 一旦止まる

  boxWidth += 30;
  box.style.width = boxWidth + "px"
  // boxを30px横長にする
  yield;
  // 一旦止まる

  boxHeight += 30;
  box.style.height = boxHeight + "px"
  // boxを30px高くする
  yield;
  // 一旦止まる

  boxWidth += 30;
  box.style.width = boxWidth + "px"
  // boxを30px横長にする
  yield;
  // 一旦止まる

  boxHeight += 30;
  box.style.height = boxHeight + "px"
  // boxを30px高くする
  yield;
  // 一旦止まる

  boxWidth += 30;
  box.style.width = boxWidth + "px"
  // boxを30px横長にする
  yield;
  // 一旦止まる
```

ハスケル子「・・・」
ハスケル子「まあ、それでもいいんですけど」
ハスケル子「`while`文使いましょう・・・」

```js
  while (boxHeight < 300) {
    boxHeight += 30;
    box.style.height = boxHeight + "px"
    yield;
  
    boxWidth += 30;
    box.style.width = boxWidth + "px"
    yield;
  }
```

ハスケル子「こうしておけば」
ハスケル子「boxの高さが`300px`になるまで繰り返してくれますよ」

ワイ「おお、ループの中でも`yield`を使えるんやね」

## 関数をチョイチョイ止めながら実行できるようになった

ワイ「でも、これで**クリックするとフワフワっと**大きくなるボックス作れる・・・？」

ハスケル子「はい、ここで`transitionend`イベントを使うんです」

ワイ「`transitionend`イベント・・・もしかして」
ワイ「`transition`によるCSSプロパティの変化が終わった時に発火されるイベントかいな・・・！？」

ハスケル子「はい」

ワイ「おお、そんな便利なイベントが。。。」

ハスケル子「そのイベントと、ジェネレーターを組み合わせるんです」

```js
const generator = fuwafuwa();
```

ハスケル子「↑まずは`fuwafuwa`関数を実行して**ジェネレータ**を受け取ります」

```js
box.addEventListener("transitionend", () => generator.next());
```

ハスケル子「↑そして、`box`の`transition`が終了するたびに」
ハスケル子「`generator.next()`が実行されるように設定しておくんです」

ワイ「なるほどな」
ワイ「`transition`による動きが終了するたびに、イベントが発火して`generator.next()`が実行されて」
ワイ「それによって次の`transition`が始まり」
ワイ「またその`transition`の動きが終わることでイベントが発火して・・・」
ワイ「って相互再帰してる感じなんやな」

ハスケル子「そうです」
ハスケル子「あとは、はじめに`box`をクリックした時にも`generator.next()`が実行されるように」
ハスケル子「イベントリスナを登録しておきます」

```js
box.addEventListener("click", () => generator.next());
```

ハスケル子「↑こうですね」
ハスケル子「実際に動かしてみると↓こんな感じです」

<p class="codepen" data-height="265" data-theme-id="0" data-default-tab="js,result" data-user="Yametaro" data-slug-hash="LYPzzOP" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="fuwafuwa generator">
  <span>See the Pen <a href="https://codepen.io/Yametaro/pen/LYPzzOP/">
  fuwafuwa generator</a> by Yametaro (<a href="https://codepen.io/Yametaro">@Yametaro</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

ワイ「おお、フワフワっと大きくなってる！」
ワイ「ジェネレーターを活用すると、関数内の処理のタイミングを自在にコントロールできんねやな・・・！」
ワイ「ありがとう、ハスケル子ちゃん」
ワイ「お礼にお小遣い**400万円**あげるわ！」

![EF66DCCF-5FEC-4764-96EA-8FA86134D5A1.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295452/1ab80a2b-6dad-ef09-efd6-5f2854842397.jpeg)


社長「（なに**売り上げを半分に**してんねん・・・！）」

**〜おしまい〜**

**※登場人物、価格設定等はフィクションです。**

## 追記1
ジェネレーター関数について学ぶなら↓こちらのサイトがおすすめです。
[**JavaScript初級者から中級者になろう　十六章第六回　ジェネレータ**](https://uhyohyo.net/javascript/16_6.html)

## 追記2
IEも対応する場合は、Babel使ってな！

## 追記3 新しい記事を書いたで！
↓こちらの記事もよろしくやで！
[**すごいHaskell、ハスケル子と学ぼう！**](https://qiita.com/Yametaro/items/d12ec13de82d221702de)