jQuery.Validate.js驗證大表單的優化


最近在項目中有遇到一個Form表單中有200多個標簽。在提交表單時網頁會出現等待時間很長,甚至會出現網頁奔潰的情況。

主要的原因是因為在使用jQuery.Validate.js進行Form驗證的時候會花銷大量時間。這些時間主要用在兩個地方:

1.表單中標簽的檢查對應jQuery.Validate.js中checkForm()方法。

2.檢查完標簽后需要顯示錯誤或成功信息對應jQuery.Validate.js中ShowErrors()方法。

 

先前我們是用的jQuery.Validate.js-1.8.0版本,我更新到最新的jQuery.Validate.js-1.15.1版本,發現驗證時間沒有得到明顯的優化。

反而會與之前的版本會有沖突,沖突的地方在無法驗證隱藏的控件,例如用了第三方的HTML編輯框插件,后面會隱藏一個textarea控件,之前低版本的會檢測到這個,但是新版本的會忽略。問題在於新版本的js默認會跳過頁面中不可見的元素。

1.8.0版本的ignore:[] 這里改為“.hidden”在checkForm()時會默認過濾掉頁面中所有的不可見元素。

這是1.15.1種checkForm的方法:

checkForm: function() {
            this.prepareForm();
            for ( var i = 0, elements = ( this.currentElements = this.elements() ); elements[ i ]; i++ ) {
                this.check( elements[ i ] );
            }
            return this.valid();
        },
elements: function() {
            var validator = this,
                rulesCache = {};

            // Select all valid inputs inside the form (no submit or reset buttons)
            return $( this.currentForm )
            .find( "input, select, textarea, [contenteditable]" )
            .not( ":submit, :reset, :image, :disabled" )
            .not( this.settings.ignore )//在這個地方會對隱藏元素進行過濾,返回的elements會少了很多隱藏的元素。
            .filter( function() {
                var name = this.name || $( this ).attr( "name" ); // For contenteditable
                if ( !name && validator.settings.debug && window.console ) {
                    console.error( "%o has no name assigned", this );
                }

                // Set form expando on contenteditable
                if ( this.hasAttribute( "contenteditable" ) ) {
                    this.form = $( this ).closest( "form" )[ 0 ];
                }

                // Select only the first element for each name, and only those with rules specified
                if ( name in rulesCache || !validator.objectLength( $( this ).rules() ) ) {
                    return false;
                }

                rulesCache[ name ] = true;
                return true;
            } );
        },

這種處理的確可以減少很多不必要元素的check。但是經過測試這里的時間提升並不是十分明顯。

但是這樣處理后反而使得項目出現了不兼容的問題,因為像HTML編輯框等需要驗證的背后隱藏元素也會被隱藏。

出於項目的需要,這里我將這個參數defaults中的ignore參數改為了input[type="hidden"]這樣解決了兼容的問題。因為這個只對<input>標簽中設置了"type=hidden"的元素忽略檢查。

 

說了這么多並沒有提到如何提升驗證性能的方面。下面討論下,由於本人也是小菜,希望大神勿噴。

上面有提到驗證所花銷的時間主要花在兩個函數上,那么我們就從這兩個函數說起:

1.checkForm().

從上面其實我們已經看出來了,將ignore設置值從而過濾掉一些隱藏的元素本身就是一種對checkForm()函數執行的優化。但是這里並沒有起到實質性的作用,因為往往表單中隱藏的元素其實並不是很多,想要得到更大的提升應該是把頁面中顯示出來但是又不需要驗證的標簽進行過濾,真正做到只去check需要check的標簽元素。這里網上有一種方法就是給每個不需要Check的元素標簽添加一個類似於“class='validate-ignore'”這樣的類,然后在elements()方法中把這樣不需要驗證的元素也過濾掉。這種做法我並沒有去實踐,因為項目中表單太多,這樣一個個去添加新的class顯的有點不現實。有興趣的朋友可以去研究一下。

2.showErrors().

這個方法之所以會花銷大量的時間。因為這個方法會使得HTML DOM樹發生改變,來顯示和修改錯誤或正確的提示信息。

原生的showErrors方法如下

默認頁面中每個需要驗證的elment都會經過這個else分支去執行defaultShowErrors()函數,而這個函數就是改變DOM樹結構的入口。所以我們在這里新增一個判斷的邏輯會提升不少的時間。新增判斷如下:

showErrors: function( errors ) {
            if ( errors ) {
                var validator = this;

                // Add items to error list and map
                $.extend( this.errorMap, errors );
                this.errorList = $.map( this.errorMap, function( message, name ) {
                    return {
                        message: message,
                        element: validator.findByName( name )[ 0 ]
                    };
                } );

                // Remove items from success list
                this.successList = $.grep( this.successList, function( element ) {
                    return !( element.name in errors );
                } );
            }
            if ( this.settings.showErrors ) {
                this.settings.showErrors.call( this, this.errorMap, this.errorList );
            } else {
                    var anyElementsNeedUpdate = false; //參數表示是否需要去更新DOM樹中的元素
                    for (var i = 0; i < this.errorList.length; i++) {
                        if (!$(this.errorList[i].element).hasClass(this.settings.errorClass)) {
                            anyElementsNeedUpdate = true;//1.當之前驗證有錯誤的元素已經修改正確即沒有了這個errorClass,需要去更新element
                            break;
                        }
                    }

                    if (!anyElementsNeedUpdate) {
                        for (var i = 0; i < this.successList.length; i++) {
                            if ($(this.successList[i]).hasClass(this.settings.errorClass)) {
                                anyElementsNeedUpdate = true;//2.當之前驗證成功的元素現在含有這個errorClass,需要去更新element
                                break;
                            }
                        }
                    }

                    if (anyElementsNeedUpdate) {//如果有上面兩種情況之一都需要去更新DOM元素,否則不應該去調用defaultShowErrors();
                        this.defaultShowErrors();
                    }
            }
        },

從這個可以明顯的看出,checkForm()函數時間沒有太大的變化。但是showErrors()時間變成了之前的十分之一。

 

經過測試這個修改對驗證功能是沒有影響的,而且性能也提升了不少。

 

參考:http://stackoverflow.com/questions/5542014/jquery-validate-large-forms-script-running-slowly


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM