jQuery.Validate.js验证大表单的优化

最近在项目中有遇到一个Form表单中有200多个标签。在提交表单时网页会出现等待时间很长,甚至会出现网页奔溃的状况。jquery

主要的缘由是由于在使用jQuery.Validate.js进行Form验证的时候会花销大量时间。这些时间主要用在两个地方:git

1.表单中标签的检查对应jQuery.Validate.js中checkForm()方法。github

2.检查完标签后须要显示错误或成功信息对应jQuery.Validate.js中ShowErrors()方法。ide

 

先前咱们是用的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。可是通过测试这里的时间提高并非十分明显。this

可是这样处理后反而使得项目出现了不兼容的问题,由于像HTML编辑框等须要验证的背后隐藏元素也会被隐藏。spa

出于项目的须要,这里我将这个参数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

相关文章
相关标签/搜索