大量のInputタグがあるページでjquery validationのSubmitがどえらい遅いのはoptions.successのせいだったかもしれない。

タイトル長ぇ。

#jquery Validationサイコー

フロントエンドのValidationでお手軽かつ無くてはならない[jQuery Validation Plugin](https://jqueryvalidation.org/)。
入力チェックが必要なところではほぼ必ず使っていたんだけど、ユーザーの操作によっては数千のチェック対象ができてしまうようなFormでチェックをかけると数秒～数十秒もブラウザごと固まってしまうという現象が出た。
(jQuery Validation Plugin v1.16.0)

![スクリーンショット (80).png](https://qiita-image-store.s3.amazonaws.com/0/199750/07e12ce9-f413-dfe1-a2d3-1f84aaadea9b.png)

why?

~~whyも何もそんな大量のタグ吐くような設計が悪い。~~

```
　　　／ ＼::/＼
　　／｡(一)::(一)｡
　 ｜::｡ﾟ(_人_)ﾟ｜　まったくもってそのとおりです
　　＼ ﾟ　`⌒´／ﾟ
　　／ ⌒ヽ￣￣ヽﾟ｡
　 / _＿＼ ＼/＼ ＼
　と＿＿)_ヽ_つ ヽ_つ

```

## プロファイリング

ChromeのデベロッパーツールでSubmit時のパフォーマンススキャンを撮ってみる。
![スクリーンショット (81).png](https://qiita-image-store.s3.amazonaws.com/0/199750/bd1d7ad0-4c02-8956-22e5-fda2dd8e55c6.png)

これはひどい。

Bottom-UpでTotal Timeでソートしてみると
![スクリーンショット (83).png](https://qiita-image-store.s3.amazonaws.com/0/199750/a36a0191-d48f-ec80-9cc1-b5e5e3fa528c.png)
あった。

EventLogで見ると
![スクリーンショット (87).png](https://qiita-image-store.s3.amazonaws.com/0/199750/710b0d59-f3ef-2213-55fd-8389d7b82b3b.png)
jquery.validation#showErrorsからの流れで起こっているらしい。

## コード詳細
[jquery\-validation/jquery\.validate\.js at 29b9c702b9c831419f9f774d2acb86f42f803e11 · jquery\-validation/jquery\-validation](https://github.com/jquery-validation/jquery-validation/blob/29b9c702b9c831419f9f774d2acb86f42f803e11/dist/jquery.validate.js)
コードから追ってみる。

### [#912 showLabel()](https://github.com/jquery-validation/jquery-validation/blob/29b9c702b9c831419f9f774d2acb86f42f803e11/dist/jquery.validate.js#L912)

｢対象のコントロールに対するエラー表示用ラベルが無ければラベルを登録しておく｣的な処理っぽい。
このために1000を超えるコントロールに対して非表示のラベルを追加する処理が走って時間がかかっているようだ。

しかしエラーが無くてもとりあえずコントロールを作っておくってのはどうなんだ。

### [#875 defaultShowErrors()](https://github.com/jquery-validation/jquery-validation/blob/29b9c702b9c831419f9f774d2acb86f42f803e11/dist/jquery.validate.js#L875)
```js:jquery.validation.js
defaultShowErrors: function() {
	var i, elements, error;
	for ( i = 0; this.errorList[ i ]; i++ ) {
		error = this.errorList[ i ];
		if ( this.settings.highlight ) {
			this.settings.highlight.call( this, error.element, this.settings.errorClass, this.settings.validClass );
		}
		this.showLabel( error.element, error.message );
	}
	if ( this.errorList.length ) {
		this.toShow = this.toShow.add( this.containers );
	}
	if ( this.settings.success ) {
		for ( i = 0; this.successList[ i ]; i++ ) {
			this.showLabel( this.successList[ i ] );
		}
	}
```

んんん? エラーがあったらthis.showLabel()、それとは関係なく `this.settings.success`ならthis.showLabel()?

### settings.successとはなんぞや

[document](https://jqueryvalidation.org/validate/)漁ると
>*success*
>Type: String or Function()
>If specified, the error label is displayed to show a valid element. If a String is given, it is added as a class to the label. If a Function is given, it is called with the label (as a jQuery object) and the validated input (as a DOM element). The label can be used to add a text like "ok!".

と、エラー表示するラベルの**エラーになっていないときの表示**を設定できるようだ。
ということは、**検証OKで何か表示する時用に必要なのであって、OKの場合とくに何も表示しないならそもそも作る必要が無い**んじゃないか･･･?

### チェックの流れをおさらいしてみる

1. \$.validator.form / \$.validator.element から element.check()が呼ばれてチェック
    1. エラーなら`formatAndAdd()`経由で`errorList`に追加される
    2. OKなら`successList`に追加
1. `showErrors()`
1.  `successList`から`errorList`のものを除外
1. `this.setting.showErrors()`か**`this.defaultShowErrors()`**
1.  `errorList`のものを`showLabel()`
1.  `this.settings.success`なら`successList`に対して`showLabel()`
1.  表示すべきものを`toShow` 表示すべきでないものを`toHide` に整理してから`hideErrors()`で非表示を処理

あ、やっぱこれOKで何も表示しないなら作る必要ないわ。

## ということで

```js
$("#myform").validate({
  success: null
});
```

にしたところ

![スクリーンショット (88).png](https://qiita-image-store.s3.amazonaws.com/0/199750/de646ea0-aeef-94f4-2289-207ba5624a82.png)

0.8秒ぐらいまで短縮できた。

~~｢Major GC(1.9MB collected)｣で160msもかかってるのはそもそもこんな構造にしてるからです。~~

```
　　　／ ＼::/＼
　　／｡(一)::(一)｡
　 ｜::｡ﾟ(_人_)ﾟ｜　すみませんすみません
　　＼ ﾟ　`⌒´／ﾟ
　　／ ⌒ヽ￣￣ヽﾟ｡
　 / _＿＼ ＼/＼ ＼
　と＿＿)_ヽ_つ ヽ_つ

```

##まとめ

jquery.validationを使ってエラーチェックする際、**エラーでなければ単純にエラー表記を消す**場合、

```js
form.validate({success: null});
```
にすべき。