Vue Internals②watcher　2-1wactherとdeps

#はじめに
Vue Internals①では全体の流れを見ていきました。
ただwatcher周りはほとんど触れていないのでVueにおいてどのような働きをするのかよく理解できませんでした。
Vue Internals②ではこのwatcherの働きとcomputed,watchについてをやっていきたいと思います。
#Watcherについて
[Vue Internals①　1-4mountComponent](https://qiita.com/stonelike8/items/4176214afc5a3c4cf61f)にてnew　watcherのgetで実際のDOMをrenderingする過程を見ました。
watcherの役割はこのrenderingにあります。![watcherdiagram.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496421/0868a65e-3cf5-22fc-49f3-5da64e257dc6.png)

ただ、re-renderingの際、何がこのwatcherのトリガーとなるのでしょうか？
答えはdefinePropertyにあります。
[Vue Internals①　1-1compile前まで](https://qiita.com/stonelike8/items/3aa7565c0c7638e899a9)でmessageをObservable化したことを思い出してみましょう。
もしvm._data.message="test"みたいにするとmessageのsetが起動して、
setの処理中にdep.Notify()という項目があり、そこからwatcherにつながります。

今回調べたいことはwactherとdep関連なんですが、そのつながりがどこで作られるかです。
先にmessageに新しい値がsetされた時の動きの略図を見て、どこでwactherとdepのつながりが作られるかを実際のコード探索で見ていくことにします。
![大まかな流れ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496421/1cace6ba-e6eb-7d40-096d-47a30ea0c98d.png)
ここで全体のwactherとは1-4mountComponentで出てきたwactherのことでexpressionが"function () {
vm.update(vm._render(), hydrating);
}"となっているやつのことです。re-renderingを担っているので全体のwactherと呼んでいます。

今欲しい情報としてはmessageのDepのsubsにどこでwactherが登録されるか？、またwactherにどこでmessageのdepが登録されるかです。なのでこの後は
①computedのwactherが作られるところ
②messageのDepが作られるところ
③messageのDepにwactherが登録されるところ、またwactherにmessageのDepが登録されるところ
を見ていこうと思います。

今回のコード

```js
<html>
<script src="https://unpkg.com/vue"></script>
<body>

<div id="vue_example">
  {{comp_message}}
</div>
</body>

<script>
var vue_example = new Vue({
  el: '#vue_example',

  data: {
    message: 'Hello Vue.js!',
  },
  computed:{
     comp_message(){
         return `comp ${this.message}`
     }
  }
})
</script>


</html>
```

Vue Internals①に細かい処理は譲り、ここではcomputed,watcher絡みのところを見ていきます。

#init~compileまで
まずmergeOptionでoptionを作るときにstratsから対応する関数を取り出してその戻り値がoptionに入ります。
この時strats.computedは
![strats.computed.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496421/bb796787-5af3-4267-98c9-34803292e575.png)

結局option[computed]={comp_message:...}となります。

次はinitStateに行くと、initData、initComputedがあります。
initDataでは①でもみましたがdataをObservableにしています。
ここでdataとnew　Observerの関係を図で見てみます。
![observeDep.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496421/a1488a56-f02b-9d54-6403-7a0fb6544ae1.png)

ここで分からなかったことはnew　Observerの存在意義で、messageに新しい値を入れるときにはdefinePropertyで設定されたsetが使われて、そのままid:3のdepが使われて対応するwatcherに行くはずなので、new　Observerを介していないんですよね・・・こうなるとid:2のdepの存在意義がわからない・・・
ともかく②messageのDepが作られるところはinitDataということですね。

initComputedに行きます。
![computedWacther.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496421/043ea543-3dcd-8715-a28c-57f867ce565f.png)

ここでcomputed用のwactherを作ります。
ここでcomputed用のwactherはoptionでlazyがtrueになっていることに注意します。これが実際にmessageの値を変えるときに役になってきます。
vm.wacthersにcomputedのwactherを追加して、
lazy=trueなのでthis.get()はここでは発火しません。
initComputedに戻って、
wacthers["comp_message"]=new　Wactherだったのでcomputedのwactherが追加され、さらに
watchers = vm._computedWatchersだったのでvm._computedWacthersにも追加されます。

defineComputedでは後にcomp_messageをgetするときのgetterを定義します。通常setterは定義されません。

![defineComputed.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496421/1ff5467d-542b-c16d-b7b9-3c10b8757c8e.png)
![createComputedGetter.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496421/de356cdc-fe46-d50b-d808-ef78424285df.png)

comp_messageをgetしようとするとcomputedGetterが起動して、vm._computedeWacthers[comp_message]からwactherを取り出す流れで使います。詳しくは後ほど。

ここまででinitComputedは終わりです。①computedのwactherが作られるところはinitComputedでした。

ここから一気にmountComponentまで飛びます。AST関連は前回と大して違いがないので省略

#mountComponent
![renderWacther.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496421/40e3d7a3-c2d0-ec1f-0c51-fbd4ddc5f20e.png)

全体のwactherを作成するところで、this.lazy=falseなのでthis.getが起動します。
ここでdepsにwactherが追加されるのですがpushTargetとpopTargetという関数が重要になってきます。
動きを図で見てみましょう。
![pushAndpopTarget.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496421/57f199ae-ad25-aa9f-adb7-cb907e0af141.png)
pushTargetはwactherをtargetStackにpushして、DepTargetをそのwactherとします。
popTargetはtargetStackからpopしてDepTargetをStackの頂点のwactherとします。

DepTargetはglobalなので、どのdepからDepTargetを見ても同じwactherなので注意しましょう。
今のDepTargetが全体のwactherであることを念頭に置いて、

```js
(function anonymous(
) {
with(this){return _c('div',{attrs:{"id":"vue_example"}},[_v("\n  "+_s(comp_message)+"\n")])}
})
```
の実行まで飛びます。
ここでcomp_messageの値を得るときにcomputedGetterが起動するのでした。
computedのwacther.evaluate()に行きます。

```js:computedWacther
Watcher.prototype.evaluate = function evaluate () {
    this.value = this.get();
    this.dirty = false;
  };
```

ここで2度目のpushTargetで今度はcomputedのwactherをpushします。動きは上記の図を思い出してください。
DepTargetはcomputedのwactherに。
computedのwactherのgetterはcomp_messageでした。

```js
 comp_message(){
         return `comp ${this.message}`
     }
```
messageを取得するときに①astを中心にでもやった通り、messageのgetterが呼ばれることに注意してください。
![messageGetter.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496421/b24d3e8c-4eb8-b2c2-222d-db446c8b37b6.png)
さて、ここでDep.targetは今computedのwactherでした。
なのでmessageのdep.depend()が呼ばれます。

```js
Dep.prototype.depend = function depend () {
    if (Dep.target) {
      Dep.target.addDep(this);
    }
  };
```
![wactheraddDep.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496421/1d58ba89-63c6-3468-c321-ee202aa4d564.png)
addDepによってmessageのdepのsubsにcomputedのwactherが追加されました。

③messageのDepにwactherが登録されるところはmessageのgetterからでした。

comuptedのwactherのgetに戻り、次はpopTargetです。
ここでDepTargetが全体のwactherに戻ります。

cleanupDepsに行きます。
![computedWactherCleanup.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496421/96de1ac2-5132-737e-6644-47790854d2c3.png)
ここでnewDepsからDepsに移ります。
newDepsはdep.depned→Dep.target.addDep内でwactherにnewDepsが追加されていました。


③のwactherにdepsを登録するのはcleanupDepsでした。
最初はnewDepsに入れてそれからDepsに移す流れです。

computedGetterに戻って、watcher.depend()へ

```js
Watcher.prototype.depend = function depend () {
    var i = this.deps.length;
    while (i--) {
      this.deps[i].depend();
    }
  };
```
今回はcomputedのwactherのdepsはさっき追加した。messageのdepのみなので、そのdep.depend()だけですね。

今のDep.targetが全体のwacherで会ったことを思い出すとmessageのdepのsubsに全体のwactherが追加されてこれでmessageのdepはcomputedと全体のwacther二つがあることになります。

まとめると、①全体のwacther.get()→②computedのwatcher.get()でcomputedGetterが呼ばれる、computedGetterではまず②でpushしたcomputedのwactherをmessageのdepに入れて、そのあとに①でpushしたwactherもmessageのdepに入れました。

wactherにdepsが追加されるのはdep.depnedでnewDepsとしていったん入った後、watcher.get()のcleanupDepsでnewDepsからDepsするときです。

図でもまとめてみましょう。![depsの追加.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496421/0f231e88-cf22-3cbd-3c8c-5742d641e104.png)

後の工程は①ASTを中心にでやったことと同じです。
ここまでで、wactherの生成、deps↔wacherの追加されるタイミングがわかったと思います。
ようやく準備も整ったので次回実際にmessageに新しい値を入れた後の動きを見ましょう。