四重奏9:快板| 性能

当创建四方数据验证库时,将设置以下标志:



在本文中,我想考虑性能quartet及其原因。


关于简洁与简洁的文章将于4月4日发布。


我们将quartet与另一个比较流行的ajv进行比较,探索这一方面


你好,世界


我们将编写最简单的测试,以查看值是否为字符串“ Hello World!”。


为了比较验证库,需要我们将验证的数据。因此,对于此任务,我们具有有效和无效数据的此类集合。


const valids = ["Hello World!"];
const invalids = [null, false, undefined, "", 1, Infinity, "Hello World"];

联合会


和往常一样,这一切都从导入开始:


const Ajv = require("ajv");

创建“编译器”的实例:


const ajv = new Ajv();

Ajv以JSON方案的形式接受经过验证的类型描述


让我们为任务创建一个合适的方案。


const helloWorldSchema = {
  type: "string",
  enum: ["Hello World!"]
};

接下来,有必要“编译”验证函数,即从电路中获取一个函数,该函数将等待输入数据true,如果验证成功,则在输出处返回,否则将返回false


const ajvValidator = ajv.compile(helloWorldSchema);

做完了!


benchmark.


, :


Ajv Build
661,639 ops/sec
354,725 ops/sec
628,443 ops/sec
659,900 ops/sec
557,037 ops/sec

: 572,349 ops/sec

:


for (let i = 0; i < valids.length; i++) {
  ajvValidator(valids[i]);
}
for (let i = 0; i < invalids.length; i++) {
  ajvValidator(invalids[i]);
}

:


Ajv Validation

21,452,228 ops/sec
 3,066,770 ops/sec
 4,522,850 ops/sec
 2,522,777 ops/sec
 2,741,310 ops/sec

: 6,861,187 ops/sec

— , .


quartet


є «»:


const { v } = require("quartet");

:


const quartetValidator = v("Hello World!");

:


Quartet 9: Allegro Build

6,019,078 ops/sec
3,893,780 ops/sec
2,712,363 ops/sec
5,926,415 ops/sec
2,729,369 ops/sec

: 4,256,201 ops/sec

:


for (let i = 0; i < valids.length; i++) {
  quartetValidator(valids[i]);
}
for (let i = 0; i < invalids.length; i++) {
  quartetValidator(invalids[i]);
}

:


Quartet 9: Allegro Validation

15,073,432 ops/sec
13,711,573 ops/sec
13,123,812 ops/sec
25,617,225 ops/sec
17,588,846 ops/sec

: 17,022,977 ops/sec

:


图片


图片



:


console.log("Function");
console.log(quartetValidator.toString());

:


function (value) { return value === c; }

c — , .



. , , .



. API. , :


interface Person {
  id: number; //   
  name: string; //  
  phone: string | null; // null  12  
  phoneBook: {
    [name: string]: string; // 12  
  };
  gender: "male" | "female";
}


const valids = [
  {
    id: 1,
    name: "andrew",
    phone: "380975003434",
    phoneBook: {
      andrew: "380975003434",
      bohdan: "380975003434",
      vasilina: "380975003434"
    },
    gender: "male"
  },
  {
    id: 2,
    name: "bohdan",
    phone: null,
    phoneBook: {},
    gender: "male"
  },
  {
    id: 3,
    name: "Elena",
    phone: null,
    phoneBook: {
      siroja: "380975003434"
    },
    gender: "female"
  }
];

const invalids = [
  null, //  
  false, //  
  undefined, //  
  "", //  
  1, //  
  Infinity, //  
  "Hello World", //  
  {
    id: 0, //   
    name: "andrew",
    phone: "380975003434",
    phoneBook: {
      andrew: "380975003434",
      bohdan: "380975003434",
      vasilina: "380975003434"
    },
    gender: "male"
  },
  {
    //  id
    name: "andrew",
    phone: "380975003434",
    phoneBook: {
      andrew: "380975003434",
      bohdan: "380975003434",
      vasilina: "380975003434"
    },
    gender: "male"
  },
  {
    id: 1.5, //  
    name: "andrew",
    phone: "380975003434",
    phoneBook: {
      andrew: "380975003434",
      bohdan: "380975003434",
      vasilina: "380975003434"
    },
    gender: "male"
  },
  {
    id: 1,
    name: "", //  
    phone: "380975003434",
    phoneBook: {
      andrew: "380975003434",
      bohdan: "380975003434",
      vasilina: "380975003434"
    },
    gender: "male"
  },
  {
    id: 1,
    //  name
    phone: "380975003434",
    phoneBook: {
      andrew: "380975003434",
      bohdan: "380975003434",
      vasilina: "380975003434"
    },
    gender: "male"
  },
  {
    id: 1,
    name: "andrew",
    phone: "38097500434", // 11 
    phoneBook: {
      andrew: "380975003434",
      bohdan: "380975003434",
      vasilina: "380975003434"
    },
    gender: "male"
  },
  {
    id: 1,
    name: "andrew",
    //  phone
    phoneBook: {
      andrew: "380975003434",
      bohdan: "380975003434",
      vasilina: "380975003434"
    },
    gender: "male"
  },
  {
    id: 1,
    name: "andrew",
    phone: "380975003434",
    phoneBook: {
      andrew: "380975003434",
      bohdan: "380975003434",
      vasilina: "38097503434" // 11 
    },
    gender: "male"
  },
  {
    id: 1,
    name: "andrew",
    phone: "380975003434",
    // phoneBook 
    gender: "male"
  },
  {
    id: 1,
    name: "andrew",
    phone: "380975003434",
    phoneBook: {
      andrew: "380975003434",
      bohdan: "380975003434",
      vasilina: "380975003434"
    },
    gender: "Male" // 'male'
  },
  {
    id: 1,
    name: "andrew",
    phone: "380975003434",
    phoneBook: {
      andrew: "380975003434",
      bohdan: "380975003434",
      vasilina: "380975003434"
    }
  }
];

ajv


:


const personSchema = {
  type: "object",
  required: ["id", "name", "phone", "phoneBook", "gender"],
  properties: {
    id: {
      type: "integer",
      exclusiveMinimum: 0
    },
    name: {
      type: "string",
      minLength: 1
    },
    phone: {
      anyOf: [
        { type: "null" },
        {
          type: "string",
          pattern: "^\\d{12}$"
        }
      ]
    },
    phoneBook: {
      type: "object",
      additionalProperties: {
        type: "string",
        pattern: "^\\d{12}$"
      }
    },
    gender: {
      type: "string",
      enum: ["male", "female"]
    }
  }
};

:


const ajvCheckPerson = ajv.compile(personSchema);

:


Ajv Build

79,476 ops/sec
78,334 ops/sec
61,752 ops/sec
77,395 ops/sec
78,539 ops/sec
51,922 ops/sec
80,031 ops/sec
77,687 ops/sec
65,439 ops/sec
79,805 ops/sec

: 73,038 ops/sec

:


for (let i = 0; i < valids.length; i++) {
  ajvCheckPerson(valids[i]);
}
for (let i = 0; i < invalids.length; i++) {
  ajvCheckPerson(invalids[i]);
}

:


Ajv Validation

227,640 ops/sec
301,134 ops/sec
190,450 ops/sec
195,595 ops/sec
384,380 ops/sec
193,358 ops/sec
385,280 ops/sec
239,009 ops/sec
193,832 ops/sec
392,808 ops/sec

: 270,349 ops/sec

quartet


:


const quartetCheckPerson = v({
  id: v.and(v.safeInteger, v.positive),
  name: v.and(v.string, v.minLength(1)),
  phone: [null, v.test(/^\d{12}$/)],
  phoneBook: {
    [v.rest]: v.test(/^\d{12}$/)
  },
  gender: ["male", "female"]
});

:


Quartet 9: Allegro Build

35,564 ops/sec
14,401 ops/sec
15,438 ops/sec
26,852 ops/sec
33,935 ops/sec
16,010 ops/sec
34,550 ops/sec
33,148 ops/sec
16,037 ops/sec
36,828 ops/sec

: 26,276 ops/sec

:


for (let i = 0; i < valids.length; i++) {
  quartetCheckPerson(valids[i]);
}
for (let i = 0; i < invalids.length; i++) {
  quartetCheckPerson(invalids[i]);
}

, :


Quartet 9: Allegro Validation

237,059 ops/sec
435,844 ops/sec
248,021 ops/sec
238,931 ops/sec
416,993 ops/sec
281,904 ops/sec
439,975 ops/sec
242,074 ops/sec
330,487 ops/sec
421,704 ops/sec

: 329,299 ops/sec

:


图片
图片



, , quartetCheckPerson .


console.log(quartetCheckPerson.toString());
console.log({ ...quartetCheckPerson });


function validator(value) {
  if (value == null) return false
  if (!Number.isSafeInteger(value.id)) return false
  if (value.id <= 0) return false
  if (typeof value.name !== 'string') return false
  if (value.name == null || value.name.length < 1) return false
  if (!validator["value.phone"](value.phone)) return false
  if (value.phoneBook == null) return false
  validator.keys = Object.keys(value.phoneBook)
  for (let i = 0; i < validator.keys.length; i++) {
    validator.elem = value.phoneBook[validator.keys[i]]
    if (!validator["tester-1"].test(validator.elem)) return false
  }

  if (!validator["value.gender"](value.gender)) return false
  return true
};

// Check person properties
{
  'value.phone': function validator(value) {
    if (value === null) return true;
    if (validator.tester.test(value)) return true;
    return false
  }
  ['value.phone']['tester']: /^\d{12}$/,
  'tester-1': /^\d{12}$/,
  'value.gender': function validator(value) {
    if (validator.__validValuesDict[value] === true) return true
    return false
  },
  ['value.gender']['__validValuesDict']: {
    male: true,
    female: true
  }
}

— , — .


:


ajv


— ajv , errors.


quartet


quartet - .


:


1) v.custom. — , explanations , . — —


:


const checkId = v(v.and(v.safeInteger, v.positive));
const checkName = v(v.and(v.string, v.minLength(1)));
const checkPhone = v([null, v.test(/^\d{12}$/)]);
const checkPhoneBookItem = v(v.test(/^\d{12}$/));
const checkGender = v(["male", "female"]);

const quartetCheckPerson = v({
    id: v.custom(checkId, "id"),
    name: v.custom(checkName, "name"),
    phone: v.custom(checkPhone, "phone"),
    phoneBook: {
      [v.rest]: v.custom(checkPhoneBookItem, "phoneBook")
    },
    gender: v.custom(checkGender, "gender")
  }); 

// quartetCheckPerson({}) // false
// quartetCheckPerson.explanations // ['id']

进行测量:
图片
图片


2)第二种方法更具意识形态-默认情况下使用自定义说明。一旦验证者之一返回false,就会调用errorBoundary函数。


import { quartet } from 'quartet'
const v = quartet({
  errorBoundary(explanations, { value, id, schema, innerExplanations }) {
    explanations.push(...innerExplanations, { value, id, schema })
  }
})

const checkPerson = v({
  id: v.and(v.safeInteger, v.positive),
  name: v.and(v.string, v.minLength(1)),
  phone: [null, v.test(/^\d{12}$/)],
  phoneBook: {
    [v.rest]: v.test(/^\d{12}$/)
  },
  gender: ["male", "female"]
});

// checkPerson(null) // false
// checkPerson.explanations // [{ value: null, id: 'value', schema: { id: ... }]

进行测量:


图片
图片


摘要


比较产生了混合结果。对于那些需要性能和解释的人-选择ajv。对于不需要解释残疾的人,可以选择四重奏,并通过更具可读性和表现力的方案获得更高的性能。
这个结果使我感到鼓舞。我希望读者可以尝试quartet@9实践。


感谢您的阅读,有趣的阅读评论。


All Articles