LoginSignup
4
2

More than 5 years have passed since last update.

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

Last updated at Posted at 2017-12-04

タイトル長ぇ。

jquery Validationサイコー

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

スクリーンショット (80).png

why?

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

   / \::/\
  /。(一)::(一)。
  |::。゚(_人_)゚| まったくもってそのとおりです
  \ ゚ `⌒´/゚
  / ⌒ヽ ̄ ̄ヽ゚。
  / __\ \/\ \
 と__)_ヽ_つ ヽ_つ

プロファイリング

ChromeのデベロッパーツールでSubmit時のパフォーマンススキャンを撮ってみる。
スクリーンショット (81).png

これはひどい。

Bottom-UpでTotal Timeでソートしてみると
スクリーンショット (83).png
あった。

EventLogで見ると
スクリーンショット (87).png
jquery.validation#showErrorsからの流れで起こっているらしい。

コード詳細

jquery-validation/jquery.validate.js at 29b9c702b9c831419f9f774d2acb86f42f803e11 · jquery-validation/jquery-validation
コードから追ってみる。

#912 showLabel()

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

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

#875 defaultShowErrors()

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漁ると

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に追加
  2. showErrors()
  3. successListからerrorListのものを除外
  4. this.setting.showErrors()this.defaultShowErrors()
  5. errorListのものをshowLabel()
  6. this.settings.successならsuccessListに対してshowLabel()
  7. 表示すべきものをtoShow 表示すべきでないものをtoHide に整理してからhideErrors()で非表示を処理

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

ということで

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

にしたところ

スクリーンショット (88).png

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

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

   / \::/\
  /。(一)::(一)。
  |::。゚(_人_)゚| すみませんすみません
  \ ゚ `⌒´/゚
  / ⌒ヽ ̄ ̄ヽ゚。
  / __\ \/\ \
 と__)_ヽ_つ ヽ_つ

まとめ

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

form.validate({success: null});

にすべき。

4
2
0

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
4
2