Rc-Form源码分析

作者:姚观寿,高级前端工程师,天虹数字灵智科技

前段时间因为公司需要做比较复杂的表单校验,多层嵌套和动态form组件创建,为了能够写出更好的form表单组件我特意去看了下他底层源码, Rc-Form其实就是阿里ant design form的底层源码,今天我们来学习下Rc-Form源码分析,学习完以后我们在使用ant design form 会更加游刃有余。

Rc-Form功能: 主要是用来 创建和收集字段的数据和校验字段错误信息,让开发程序员少代码能实现这个的功能。

接下来我们来一起看看Rc-Form整个代码构思,Rc-Form 主要分为几个模块 createBaseForm 的 getForm 向整个组件props注入 setFieldsValue, getFieldsValue,resetFields,validateFields ,getFieldDecorator, getFieldProps。

createFieldsStore 是用来存储字段fields value 和 error 和 方法。里面用到了 订阅和发布模式。类似于redux的一个东西,主要核心方法:setFields,resetFields,getFieldValuePropValue, clearField,getFieldsError。

代码和程序流程图思维导图

  • 如果你觉得不错,请帮我在git仓库上点赞,谢谢了,你的支持是我开源的动力。
  • git逐行分析源码地址 : https://github.com/qq281113270/antd-rcfom.git
  • Rc-Form 源码基本构思: http://naotu.baidu.com/file/5548c203caa4d01bccc80660deec923d?token=42d2b5b01a256c28

    Rc-Form 源码详细分析: http://naotu.baidu.com/file/bb9abeca5d9a6878c6a27202dd9378dd?token=9768523373fe9934

    Rc-Form文件分析

    接下来我们细说整个代码。

    首先我们需要把这个code下载下来。第一步安装node_modules

    npm i --save rc-form

    这样就可以把rc-form源码下载下来了,

    然后我们最好启动一个react项目,当然我们可以使用react-create-app创建一个react项目。

    然后把rc-form源码包源码最好拷贝到react项目中的src 目录中,这样后期我们在rc-form组件中写上注释,还可以保留。

    下载下来之后_rc-form@2.4.11@rc-form 包会有几个文件夹目录。一般webpack 默认引用的的是es包。

     outputpath
    ├── dist # umd module
        UMD(Universal Module Definition)是 AMD 和 CommonJS 的糅合,跨平台的解决方案
        UMD 打包出来的文件可以直接通过 script 插件 html 中使用
    ;(function(root, factory) {
    if (typeof exports === 'object' && typeof module === 'object')
      module.exports = factory()
    else if (typeof define === 'function' && define.amd) define([], factory)
    else if (typeof exports === 'object') exports['A'] = factory()
    else root['A'] = factory()
    })(window, function() {
    //...
    })
       
    ├── es   # es module
    ES Module 不是对象,是使用 export 显示指定输出,再通过 import 输入。此法为编译时加载,编译时遇到 import 就会生成一个只读引用。等到运行时就会根据此引用去被加载的模块取值。所以不会加载模块所有方法,仅取所需。
    export const m = 1
    export {
    m
    }


    ├── lib   # commonjs module
      CommonJS 模块是对象,是运行时加载,运行时才把模块挂载在 exports 之上(加载整个模块的所有),加载模块其实就是查找对象属性。
    导出使用 module.exports,也可以 exports。就是在此对象上挂属性。exports 指向 module.exports,即 exports= module.exports
     
    加载模块通过 require 关键字引用
    module.exports.add = function add() {
    return
    }
    exports.sub = function sub() {
    return
    }

    const a = require('a.js')

    如果你喜欢 当然 也可以直接看 cdn 包。

    接下来我们来看文件

    createBaseForm.js

    这个js主要用于创造基本的 form 组件

    他的实现主要利用了react 的 hoc 高级组件方式实现,原理其实就是返回一个匿名函数然后在函数中传递一个子组件进来,然后利用 hoc 高阶组件 把props的form 注入进来给children组件,实现例子,这里用到以前的一些知识点 比如闭包,函数式编程,函数式柯里化。所以下面我们来简单的实现一个props.form 注入 子组件中

     // 因为第一层需要传递参数
    const createForm = (options) => {
    return (Component) => {
      return class Form extends React.Component {
        getForm() {
          return {
            getFieldsValue: () => {}, // 获取字段值得函数
            getFieldValue: () => {}, // 获取单个值得函数
            getFieldInstance: () => {}, // 获取字段实例
            setFieldsValue: () => {}, // 设置字段值
            setFields: () => {}, // 设置字段 新的值
            setFieldsInitialValue: () => {}, // 设置初始化值的函数
            getFieldDecorator: () => {}, // 用于和表单进行双向绑定,详见下方描述 装饰组件,促进双向绑定的修饰器
            getFieldProps: () => {}, // 创建待验证的表单 设置字段元数据,返回 计算被修饰组件的属性
            getFieldsError: () => {}, //获取一组输入控件的 Error ,如不传入参数,则获取全部组件的 Error
            getFieldError: () => {}, //获取某个输入控件的 Error
            isFieldValidating: () => {}, //判断一个输入控件是否在校验状态
            isFieldsValidating: () => {}, // 判断字段是否在校验中
            isFieldsTouched: () => {}, //判断是否任一输入控件经历过 getFieldDecorator 的值收集时机 options.trigger
            isFieldTouched: () => {}, //判断一个输入控件是否经历过 getFieldDecorator 的值收集时机 options.trigger
            isSubmitting: () => {}, // 是否在 提交状态
            submit: () => {}, // 表单提交函数
            validateFields: () => {}, //验证字段,返回promise
            resetFields: () => {}, // 重置字段
          };
        }
        render() {
          const props = {
            form: this.getForm.call(this),
          };
          return <Component {...props} />;
        }
      };
    };
    };

    class BaseForm extends React.Component {
    constructor(props) {
      super(props);
    }

    componentDidMount() {
      console.log(this.props);
      debugger;
    }
    render() {
      return (
        <form>
          <input />
          <select>
            <option>1</option>
          </select>
        </form>
      );
    }
    }

    const Form = createForm({ name: "abc" })(BaseForm);

    ReactDOM.render(<Form />, document.getElementById("example"));

    连接createFieldsStore类的各种方法

    props的form上的方法大多数是调用createFieldsStore类的方法,通过调用createFieldsStore 的各种方法实现控制字段的增删改查。

    createFieldsStore.js

    createFieldsStore 可以理解是用于存储字段信息值,包括字段值和校验,错误信息 还有 事件等。可以理解成仓库比如像redux这种。然后这个类会有各种方法包括增删改查字段,校验字段等。

    数据格式:

    每创建一个form 表单( 比如 createForm()(RcForm) ) 就会实例化createFieldsStore 一次,同时该createFieldsStore 就会产生一个实例属性fields和一个实例属性fieldsMeta

    fields 是validateFields 调用回调函数之后,传递给用户的field值,用来记录用户输入值的对象。 数据格式为字段名称作为key, 里面 是对象value值 :

     {
    fieldName:{
      value: "1"
    }
    }
    createBaseForm(options)(Component) 
    //options 为整个表单配置的参数
    // Component 表单组件 为改组件注入props.form


    createBaseForm 组件的 getInitialState
    创建 初始化 fieldsStore

    getFieldDecorator

    // 用于和表单进行双向绑定,详见下方描述 装饰组件,促进双向绑定的修饰器

    实际上他主要也是调用getFieldProps 方法,

    通过闭包,hoc高阶组建,利用React.cloneElement 隐形 把 props 的value和onChange注入 到组建中

    以下片段代码

        // 用于和表单进行双向绑定,详见下方描述 装饰组件,促进双向绑定的修饰器
        getFieldDecorator: function getFieldDecorator(
          name, // 字段名称
          fieldOption // 字段设置参数
        ) {
          var _this2 = this;
          // 创建待验证的表单 设置字段元数据,返回 计算被修饰组件的属性
          var props = this.getFieldProps(name, fieldOption);
          return function (
            fieldElem // 组件 也可以理解为react 的 vnode 虚拟dom
          ) {
          // .....
          return React.cloneElement(
              fieldElem, //原来的vnode
              // props 属性
              _extends(
                {},
                props, // 用户传进来的 props 属性
                // 获取value 属性值
                _this2.fieldsStore.getFieldValuePropValue(fieldMeta)
              )
            );
           
          .....
           

    getFieldProps

    该方法主要是返回 onChange 方法和 value 让组件变成受控组件,促进双向绑定的修饰器。

    调用trigger (onCollectValidate)和validateTriggers方法(onCollect)

    为Meta 类添加一个 MetaFiel 对象

     // 获取单个字段的getFieldMeta 对象 这个是字段 信息 和设置 Meta 初始化值作用
    //
    var fieldMeta = this.fieldsStore.getFieldMeta(name);
        //获取字段选项参数
          var fieldOption = _extends(
            {
              name: name, // 字段名称
              trigger: DEFAULT_TRIGGER, //onChange 收集子节点的值的时机
              valuePropName: "value", // 字段value
              validate: [], // 验证 空数组
            },
            usersFieldOption // 字段选项参数
          );
            /// ... 省略代码
           
            return inputProps;

    normalizeValidateRules 获取字段验证规则

    /*
    获取收集字段验证规则,并添加到队列中
    */
    function normalizeValidateRules(
      validate, // 收集验证规则字段存储
      rules, // 字段验证规则
      validateTrigger // 触发字段验证规则事件数组
      ) {

    var validateRules = validate.map(function (item) {
      var newItem = _extends({}, item, {
        trigger: item.trigger || [],
      });
      if (typeof newItem.trigger === "string") {
        newItem.trigger = [newItem.trigger];
      }
      return newItem;
    });
    console.log("validateRules=", validateRules);
    // 如果该字段有验证规则泽添加到validateRules队列中
    if (rules) {
      validateRules.push({
        trigger: validateTrigger ? [].concat(validateTrigger) : [],
        rules: rules,
      });
    }
    console.log("validateTrigger=", validateTrigger);
    console.log("validateRules=", validateRules);
    return validateRules;
    }

    getValidateTriggers

    从normalizeValidateRules 中获取到的validateRules过滤成一个数组只要item.trigger属性该属性一般为onChange事件。

    通过获取到的trigger和validateTriggers来判断然后调用getCacheBind去给form表单组件绑定onChange事件和校验器。

    如果trigger && validateTriggers.indexOf(trigger) === -1 则表示当前form表单 并没有rules校验器。然后调用getCacheBind绑定onCollectCommon 函数 dom从原生获取值。 并且返回value值,name,fieldMeta。

    而trigger && validateTriggers.indexOf(trigger) !== -1 则表示当前form表单 有rules校验器。 的情况下onCollectValidate dom从原生获取值。 并且返回value值,name,fieldMeta,并且校验字段。

    function getValidateTriggers(validateRules) {
    return validateRules
      .filter(function (item) {
        //过滤数据
        return !!item.rules && item.rules.length;
      })
      .map(function (item) {
        //只要获取trigger 一般为change
        return item.trigger;
      })
      .reduce(function (pre, curr) {
        // 连接数组
        return pre.concat(curr);
      }, []);
    }

    getCacheBind 绑定onChange事件,并且返回事件对象

          // 组件事件绑定等 这里一般指的是收集onChange事件,然后返回事件对象
        getCacheBind: function getCacheBind(name, action, fn) {
          // 判断有没有绑定缓存,如果没有则先给一个空的对象
          if (!this.cachedBind[name]) {
            this.cachedBind[name] = {};
          }
          // 获取缓存
          var cache = this.cachedBind[name];
          //如果获取不到缓存那么就设置缓存
          if (!cache[action] || cache[action].oriFn !== fn) {
            cache[action] = {
              // 事件固定传参
              fn: fn.bind(this, name, action),
              oriFn: fn,
            };
          }
          //返回缓存中的fn函数
          return cache[action].fn;
        },

    onCollectValidate 收集验证 onchange 事件

    调用onCollectCommon 方法去调用onChange事件

    调用validateFieldsInternal 做校验并且调用 setFields 设置字段值

      // 收集验证 onchange 事件
        onCollectValidate: function onCollectValidate(name_, action) {
          console.log("arguments=", arguments);
          console.log("onCollectValidate===========");
          for (
            var _len2 = arguments.length,
              args = Array(_len2 > 2 ? _len2 - 2 : 0),
              _key2 = 2;
            _key2 < _len2;
            _key2++
          ) {
            // 收集大于2个参数组成数组存放在args数组中
            args[_key2 - 2] = arguments[_key2];
          }
          // 收集设置字段 从事件中获取值 和从事件中设置值
          var _onCollectCommon2 = this.onCollectCommon(name_, action, args),
            // 获取字段
            field = _onCollectCommon2.field,
            // 获取字段存储的对象
            fieldMeta = _onCollectCommon2.fieldMeta;
          // 新的字段
          var newField = _extends({}, field, {
            dirty: true, //检查校验字段 标志dirty 为true
          });
          // 检查校验字段 标志dirty 为true
          this.fieldsStore.setFieldsAsDirty();
          //内部验证字段
          this.validateFieldsInternal([newField], {
            action: action,
            options: {
              firstFields: !!fieldMeta.validateFirst, //当某一规则校验不通过时,是否停止剩下的规则的校验
            },
          });
        },

    onCollectCommon 收集 事件中获取值

    onCollectCommon 收集 事件中获取值 ,调用onChange事件,返回name,field,fieldMeta 对象

    onCollectCommon: function onCollectCommon(
        name, // 字段名称
        action, // 事件
        args // 事件event 参数
        ) {
        // 获取单个字段的getFieldMeta 对象 这个是字段 信息 和设置 Meta 初始化值作用
        var fieldMeta = this.fieldsStore.getFieldMeta(name);
        console.log('fieldMeta=',fieldMeta)
        console.log('action=',fieldMeta)
         
        // 判断fieldMeta 中有 事件么 如果有有则执行事件
        if (fieldMeta[action]) {
          // 执行onChange方法
          fieldMeta[action].apply(
            fieldMeta,
            // 数组去重
            _toConsumableArray(args)
          );
        } else if (
          //原始组件的的props 属性
          fieldMeta.originalProps &&
          //原始组件的的props 属性 事件
          fieldMeta.originalProps[action]
        ) {
          var _fieldMeta$originalPr;
          // 执行onChange
          (_fieldMeta$originalPr = fieldMeta.originalProps)[action].apply(
            _fieldMeta$originalPr,
            // 数组去重
            _toConsumableArray(args)
          );
        }
        //从原生dom onChange事件中获取值
        var value = fieldMeta.getValueFromEvent
          ? fieldMeta.getValueFromEvent.apply(
              fieldMeta,
              // 数组去重
              _toConsumableArray(args)
            )
          : getValueFromEvent.apply(
              undefined,
              // 数组去重
              _toConsumableArray(args)
            );
        // 如果表单有传递onValuesChange 函数进来 则触发
        if (onValuesChange && value !== this.fieldsStore.getFieldValue(name)) {
          // 获取所有值
          var valuesAll = this.fieldsStore.getAllValues();
          var valuesAllSet = {};
          valuesAll[name] = value;
          // 循环所有值
          Object.keys(valuesAll).forEach(function (key) {
            //设置值
            return set(valuesAllSet, key, valuesAll[key]);
          });
          // 更新值
          onValuesChange(
            // 浅拷贝
            _extends(
              // 为对象添加 描述设置属性 或者是为对象添加 属性或者方法
              _defineProperty({}, formPropName, this.getForm()),
              this.props
            ),
            // 设置值
            set({}, name, value),
            // 原来所有值对象
            valuesAllSet
          );
        }
        // 获取字段
        var field = this.fieldsStore.getField(name);
        return {
          // 字段名称
          name: name,
          // 合并新的字段
          field: _extends({}, field, { value: value, touched: true }),
          // 字段存储对象
          fieldMeta: fieldMeta,
        };
      },
        //字段内部验证字段
        validateFieldsInternal: function validateFieldsInternal(
          fields, // 需要校验的字段
          _ref, // 拓展参数选项
          callback // 回调函数
        ) {
          var _this7 = this;

          var fieldNames = _ref.fieldNames, // 字段名称
            action = _ref.action, // 字段事件 一般为onchange
            _ref$options = _ref.options, // getFieldDecorator 参数
            options = _ref$options === undefined ? {} : _ref$options;

          var allRules = {}; // 校验规则
          var allValues = {}; // 值
          var allFields = {}; //字段
          var alreadyErrors = {}; // 错误信息
          // 循环字段
          fields.forEach(function (field) {
            // 获取字段名称
            var name = field.name;
            if (options.force !== true && field.dirty === false) {
              // 字段错误信息
              if (field.errors) {
                // 如果有错误信息存起来
                set(alreadyErrors, name, { errors: field.errors });
              }
              return;
            }
            // 获取单个字段的getFieldMeta 对象 这个是字段 信息 和设置 Meta 初始化值作用
            var fieldMeta = _this7.fieldsStore.getFieldMeta(name);
            //浅拷贝字段
            var newField = _extends({}, field);
            //设置新的字段错误信息为undefined
            newField.errors = undefined;
            // 设置已经验证过
            newField.validating = true;
                //
            newField.dirty = true;
            //获取得到验证规则
            allRules[name] = _this7.getRules(fieldMeta, action);
            // 获取值
            allValues[name] = newField.value;
            //字段名称
            allFields[name] = newField;
          });
          // 设置字段
          this.setFields(allFields);
          // in case normalize 以防正常化 获取全部值
          Object.keys(allValues).forEach(function (f) {
            // 获取值
            allValues[f] = _this7.fieldsStore.getFieldValue(f);
          });
          //判断对象是否是空对象
          if (callback && isEmptyObject(allFields)) {
            callback(
              isEmptyObject(alreadyErrors) ? null : alreadyErrors,
              // 字段值
              this.fieldsStore.getFieldsValue(fieldNames)
            );
            return;
          }
           
          // 表单异步验证插件
          var validator = new AsyncValidator(allRules);
          //整个表单校验信息 一般不会传递这个
          if (validateMessages) {
            validator.messages(validateMessages);
          }
          console.log('allRules=',allRules)
          console.log('allValues=',allValues)
          validator.validate(
            allValues, // 全部值
            options, // 选项
            // 错误信息回调函数
            function (errors) {
              // 获取错误信息集合
              var errorsGroup = _extends({}, alreadyErrors);
              // 如果错误信息存在
              if (errors && errors.length) {
                // 循环错误信息
                errors.forEach(function (e) {
                  //获取字段
                  var errorFieldName = e.field;

                  var fieldName = errorFieldName;

                  // Handle using array validation rule. 句柄使用数组验证规则。
                  // ref: https://github.com/ant-design/ant-design/issues/14275
                  //如果有一个元素满足条件,则表达式返回true , 剩余的元素不会再执行检测。
                  Object.keys(allRules).some(function (ruleFieldName) {
                    var rules = allRules[ruleFieldName] || [];

                    // Exist if match rule 如果匹配规则存在
                    if (ruleFieldName === errorFieldName) {
                      fieldName = ruleFieldName;
                      return true;
                    }

                    // Skip if not match array type 如果不匹配数组类型,则跳过
                    if (
                      //如果全部元素满足条件,则表达式返回true ,
                      rules.every(function (_ref2) {
                        var type = _ref2.type;
                        return type !== "array";
                      }) ||
                      // 检查 xxx.
                      errorFieldName.indexOf(ruleFieldName + ".") !== 0
                    ) {
                      return false;
                    }

                    // Exist if match the field name 如果匹配字段名称,则存在
                    var restPath = errorFieldName.slice(ruleFieldName.length + 1);
                    if (/^\d+$/.test(restPath)) {
                      fieldName = ruleFieldName;
                      return true;
                    }

                    return false;
                  });
                  // 获取字段
                  var field = get(errorsGroup, fieldName);
                  if (typeof field !== "object" || Array.isArray(field)) {
                    // 记录错误字段
                    set(errorsGroup, fieldName, { errors: [] });
                  }
                  var fieldErrors = get(errorsGroup, fieldName.concat(".errors"));
                  //收集错误信息
                  fieldErrors.push(e);
                });
              }
              var expired = [];
              var nowAllFields = {};
              // 循环校验规则
              Object.keys(allRules).forEach(function (name) {
                //获取错误字段
                var fieldErrors = get(errorsGroup, name);
                // 获取当前字段
                var nowField = _this7.fieldsStore.getField(name);
                // avoid concurrency problems 避免并发问题
                //判断两个值是否相等
                if (!eq(nowField.value, allValues[name])) {
                  // 如果不相等
                  expired.push({
                    name: name,
                  });
                } else {
                  //如果相等
                  nowField.errors = fieldErrors && fieldErrors.errors;
                  nowField.value = allValues[name];
                  nowField.validating = false;
                  nowField.dirty = false;
                  nowAllFields[name] = nowField;
                }
              });
              // 设置字段
              _this7.setFields(nowAllFields);
              if (callback) {
                //如果有值不相等,则需要重新校验一次
                if (expired.length) {
                  expired.forEach(function (_ref3) {
                    var name = _ref3.name;

                    var fieldErrors = [
                      {
                        message: name + " need to revalidate", //需要重新验证
                        field: name,
                      },
                    ];
                    // 记录是否有错误信息
                    set(errorsGroup, name, {
                      expired: true,
                      errors: fieldErrors,
                    });
                  });
                }
                // 回调函数
                callback(
                  isEmptyObject(errorsGroup) ? null : errorsGroup,
                  _this7.fieldsStore.getFieldsValue(fieldNames)
                );
              }
            }
          );
        },

    setFields 设置form表单值

    参数:对象key与value。重新设置表单值,

    通过循环遍历form表单值新旧值对比,如果不同则更新

     function setFields(fields) {
          var _this = this;
          // 获取字段信息
          var fieldsMeta = this.fieldsMeta;
          // 新字段 和 原来字段合并
          var nowFields = _extends({}, this.fields, fields);
          // 新的值
          var nowValues = {};
          // 获取字段值
          Object.keys(fieldsMeta).forEach(function (f) {
            // 获取字段的值
            nowValues[f] = _this.getValueFromFields(
              f, // 字段名称
              nowFields // 所有字段
            );
          });
          // 循环现在的值 然后注册到Meta 中
          Object.keys(nowValues).forEach(function (f) {
            // 获取单个值
            var value = nowValues[f];
            // 获取单个字段的getFieldMeta 对象 这个是字段 信息
            var fieldMeta = _this.getFieldMeta(f);
            // 初始化值设定的一个函数 demo https://codepen.io/afc163/pen/JJVXzG?editors=0010
            if (fieldMeta && fieldMeta.normalize) {
              // 获取字段的值
              //当前值
              var nowValue = fieldMeta.normalize(
                value,
                _this.getValueFromFields(f, _this.fields),
                nowValues
              );
              //如果新的值和旧的值不相同则更新新的值
              if (nowValue !== value) {
                nowFields[f] = _extends({}, nowFields[f], {
                  value: nowValue,
                });
              }
            }
          });
          console.log('this.fields=', this.fields)
            debugger
          // 设置 字段
          this.fields = nowFields;
        },

    validateFields 表单提交 校验所有表单值。

    表单提交前做做校验。

    获取到参数通过getParams格式处理参数,这样让函数接口兼容性更强

    然后调用validateFieldsInternal去做校验

    callback 返回表单值

         //验证字段,返回promise
        validateFields: function validateFields(ns, opt, cb) {
          var _this8 = this;
          console.log("this=", this);
          console.log("this.fieldsStore=", this.fieldsStore);

       

          var pending = new Promise(function (resolve, reject) {
            // 得到参数,格式化整理转义参数
            var _getParams = getParams(ns, opt, cb),
              // 获取参数的names
              names = _getParams.names,
              // 获取参数的options 选项
              options = _getParams.options;
            // 得到参数,格式化整理转义参数
            var _getParams2 = getParams(ns, opt, cb),
              // 获取参数的回调函数
              callback = _getParams2.callback;
            // 如果回调函数
            if (!callback || typeof callback === "function") {
              var oldCb = callback;
              callback = function callback(errors, values) {
                if (oldCb) {
                  // 执行回调函数
                  oldCb(errors, values);
                }
                if (errors) {
                  // 如果有错误则执行reject
                  reject({ errors: errors, values: values });
                } else {
                  // 成功执行
                  resolve(values);
                }
              };
            }
            // 获取字段名称       从所有字段中 过滤出 maybePartialName 参数匹配到的字段
            var fieldNames = names
              ? _this8.fieldsStore.getValidFieldsFullName(names)
              : _this8.fieldsStore.getValidFieldsName();
            // 获取含有检验规则的字段
            var fields = fieldNames
              .filter(function (name) {
                // 获取单个字段的getFieldMeta 对象 这个是字段 信息 和设置 Meta 初始化值作用
                var fieldMeta = _this8.fieldsStore.getFieldMeta(name);
                //含有校验规则的字段
                return hasRules(fieldMeta.validate);
              })
              .map(function (name) {
                //获取字段
                var field = _this8.fieldsStore.getField(name);
                // 获取字段的值
                field.value = _this8.fieldsStore.getFieldValue(name);
                // 返回字段
                return field;
              });
            console.log("validateFields fields=", fields);
            // 如果没有校验字段
            if (!fields.length) {
              // 获取字段值
              callback(null, _this8.fieldsStore.getFieldsValue(fieldNames));
              return;
            }
            // 标志当某一规则校验不通过时,是否停止剩下的规则的校验
            if (!("firstFields" in options)) {
              options.firstFields = fieldNames.filter(function (name) {
                // 获取单个字段的getFieldMeta 对象 这个是字段 信息 和设置 Meta 初始化值作用
                var fieldMeta = _this8.fieldsStore.getFieldMeta(name);
                return !!fieldMeta.validateFirst; //当某一规则校验不通过时,是否停止剩下的规则的校验
              });
            }
            //字段校验
            _this8.validateFieldsInternal(
              fields,
              {
                fieldNames: fieldNames,
                options: options,
              },
              callback
            );
          });
          //俘获错误
          pending["catch"](function (e) {
            // eslint-disable-next-line no-console
            if (console.error && process.env.NODE_ENV !== "production") {
              // eslint-disable-next-line no-console
              console.error(e);
            }
            return e;
          });
          return pending;
        },