Quando a biblioteca de validação de dados do quarteto foi criada , os seguintes pontos de referência foram definidos:
Neste artigo, gostaria de considerar o desempenho quartet
e suas razões.
Um artigo sobre Brevidade e Simplicidade será no dia 4 de abril.
Vamos explorar esse aspecto em comparação entre quartet
e outro ajv muito mais popular .
Olá Mundo
Escreveremos o teste mais simples - se o valor é a sequência "Hello World!".
Para comparar as bibliotecas de validação, são necessários dados que iremos validar. Consequentemente, para esta tarefa, temos esses conjuntos de dados válidos e não válidos.
const valids = ["Hello World!"];
const invalids = [null, false, undefined, "", 1, Infinity, "Hello World"];
ajv
Como sempre, tudo começa com a importação:
const Ajv = require("ajv");
Crie uma instância do "compilador":
const ajv = new Ajv();
A entrada Ajv aceita uma descrição do tipo validado na forma de um esquema JSON .
Vamos criar um esquema apropriado para nossa tarefa.
const helloWorldSchema = {
type: "string",
enum: ["Hello World!"]
};
Em seguida, é necessário "compilar" a função de validação, ou seja, a partir do circuito, obter uma função que espere os dados de entrada e retorne na saída true
, se a validação for bem-sucedida, caso contrário, ela retornará false
.
const ajvValidator = ajv.compile(helloWorldSchema);
Feito!
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;
phoneBook: {
[name: string]: string;
};
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"
},
{
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,
phone: "380975003434",
phoneBook: {
andrew: "380975003434",
bohdan: "380975003434",
vasilina: "380975003434"
},
gender: "male"
},
{
id: 1,
name: "andrew",
phone: "38097500434",
phoneBook: {
andrew: "380975003434",
bohdan: "380975003434",
vasilina: "380975003434"
},
gender: "male"
},
{
id: 1,
name: "andrew",
phoneBook: {
andrew: "380975003434",
bohdan: "380975003434",
vasilina: "380975003434"
},
gender: "male"
},
{
id: 1,
name: "andrew",
phone: "380975003434",
phoneBook: {
andrew: "380975003434",
bohdan: "380975003434",
vasilina: "38097503434"
},
gender: "male"
},
{
id: 1,
name: "andrew",
phone: "380975003434",
gender: "male"
},
{
id: 1,
name: "andrew",
phone: "380975003434",
phoneBook: {
andrew: "380975003434",
bohdan: "380975003434",
vasilina: "380975003434"
},
gender: "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
};
{
'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")
});
Faça medições:


2) O segundo método é mais ideológico - usando explicações personalizadas por padrão. A função errorBoundary será chamada assim que um dos validadores retornar false.
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"]
});
Faça medições:


Sumário
A comparação produziu resultados mistos. Para aqueles que precisam de desempenho e explicação - escolha ajv. Para aqueles que não precisam de explicações sobre deficiências - faça o quarteto - e obtenha ainda mais desempenho com um esquema mais legível e expressivo.
Estou encorajado por este resultado. Espero que o leitor queira experimentar quartet@9
na prática.
Obrigado pela leitura, interessante para ler os comentários.