Kuartet 9: Allegro | Performa

Ketika pustaka validasi data kuartet dibuat , landmark berikut ini ditetapkan:



Dalam artikel ini, saya ingin mempertimbangkan kinerja quartetdan alasannya.


Artikel tentang Brevity dan Simplicity akan diterbitkan pada 4 April.


Kami akan mengeksplorasi aspek ini sebagai perbandingan antara quartetdan ajv yang jauh lebih populer .


Halo Dunia


Kami akan menulis tes paling sederhana - apakah nilainya adalah string "Hello World!".


Untuk membandingkan pustaka validasi, diperlukan data yang akan kami validasi. Karenanya, untuk tugas ini kami memiliki set data yang valid dan tidak valid.


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

ajv


Seperti biasa, semuanya dimulai dengan impor:


const Ajv = require("ajv");

Buat turunan dari "kompiler":


const ajv = new Ajv();

Input Ajv menerima deskripsi tipe yang divalidasi dalam bentuk skema JSON .


Mari kita buat skema yang sesuai untuk tugas kita.


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

Selanjutnya, perlu untuk "mengkompilasi" fungsi validasi, yaitu, dari rangkaian, mendapatkan fungsi yang akan menunggu input data, dan kembali pada output true, jika validasi berhasil, jika tidak maka akan kembali false.


const ajvValidator = ajv.compile(helloWorldSchema);

Selesai!


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

:


gambar


gambar



:


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

:


gambar
gambar



, , 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']

Lakukan pengukuran:
gambar
gambar


2) Metode kedua lebih ideomatik - menggunakan penjelasan khusus secara default. Fungsi errorBoundary akan dipanggil segera setelah salah satu validator mengembalikan 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"]
});

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

Lakukan pengukuran:


gambar
gambar


Ringkasan


Perbandingan menghasilkan hasil yang beragam. Bagi mereka yang membutuhkan kinerja dan penjelasan - pilih ajv. Bagi mereka yang tidak membutuhkan penjelasan tentang disabilitas - ambil kuartet - dan dapatkan kinerja lebih banyak dengan skema yang lebih mudah dibaca dan ekspresif.
Saya terdorong oleh hasil ini. Saya harap pembaca ingin mencoba quartet@9dalam praktik.


Terima kasih telah membaca, menarik untuk membaca komentar.


All Articles