Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Avoid JSON.stringify calls #2

Open
Eomm opened this issue Apr 19, 2021 · 3 comments
Open

Avoid JSON.stringify calls #2

Eomm opened this issue Apr 19, 2021 · 3 comments
Labels
good first issue Good for newcomers

Comments

@Eomm
Copy link
Member

Eomm commented Apr 19, 2021

Yes, it is so right now.

I would open an issue for it and leave it as-is right now

The solutions I see:

  • track the ajv options to write a fast-json-stringify function that serialize them instead of JSON.stringify
  • apply a new logic like:
    • check the number of keys
    • check iteratively the values (I see only primitive types as values)

Originally posted by @Eomm in #1 (comment)

@climba03003
Copy link
Member

climba03003 commented Apr 22, 2021

Benchmark Script

const { Benchmark } = require("benchmark");
const FJS = require("fast-json-stringify");

const stringify = FJS({
  type: "object",
  properties: {
    coerceTypes: {
      type: "boolean",
    },
    useDefaults: {
      type: "boolean",
    },
    removeAdditional: {
      type: "boolean",
    },
    allErrors: {
      type: "boolean",
    },
    nullable: {
      type: "boolean",
    },
  },
});

const ajvConfig = {
  coerceTypes: true,
  useDefaults: true,
  removeAdditional: true,
  allErrors: false,
  nullable: true,
};

const externalSchema = {};

const suite = new Benchmark.Suite();
suite.add("JSON.stringify", function () {
  const a = JSON.stringify(ajvConfig);
  const b = JSON.stringify(externalSchema);
  const key = `${a}${b}`;
});
suite.add("FJS", function () {
  const a = stringify(ajvConfig);
  const b = JSON.stringify(externalSchema);
  const key = `${a}${b}`;
});

suite.on("cycle", function (event) {
  console.log(String(event.target));
});
suite.on("complete", function () {
  console.log("Fastest is " + this.filter("fastest").map("name"));
});
suite.run();

Result

JSON.stringify x 1,130,049 ops/sec ±3.60% (79 runs sampled)
FJS x 6,217,771 ops/sec ±2.15% (82 runs sampled)
Fastest is FJS

Environment
Node: v14.16.0
CPU: [email protected]

@Eomm
Copy link
Member Author

Eomm commented Apr 22, 2021

The ajv options are quite a lot: https://ajv.js.org/options.html

We should keep track of all new addition if we write a schema of those settings

@climba03003
Copy link
Member

climba03003 commented Apr 23, 2021

The type below is created by referencing the type from https://github.com/ajv-validator/ajv/blob/master/lib/core.ts

Note: RemovedOptions is not added in below which contain nullable.

If we go for the schema approach, should we include all the options including RemovedOptions ?

Schema for AJV options with primitive value only

{
  type: "object",
  properties: {
    // strict mode options (NEW)
    strict: {
      $ref: "#/definitions/strictOption",
    },
    strictSchema: {
      $ref: "#/definitions/strictOption",
    },
    strictNumbers: {
      $ref: "#/definitions/strictOption",
    },
    strictTypes: {
      $ref: "#/definitions/strictOption",
    },
    strictTuples: {
      $ref: "#/definitions/strictOption",
    },
    strictRequired: {
      $ref: "#/definitions/strictOption",
    },
    allowMatchingProperties: {
      type: "boolean",
    },
    allowUnionTypes: {
      type: "boolean",
    },
    validateFormats: {
      type: "boolean",
    },
    // validation and reporting options:
    $data: {
      type: "boolean",
    },
    allErrors: {
      type: "boolean",
    },
    verbose: {
      type: "boolean",
    },
    discriminator: {
      type: "boolean",
    },
    unicodeRegExp: {
      type: "boolean",
    },
    // options to modify validated data:
    removeAdditional: {
      oneOf: [
        { type: "boolean" },
        { type: "string", enum: ["all", "failing"] },
      ],
    },
    useDefaults: {
      oneOf: [{ type: "boolean" }, { type: "string", enum: ["empty"] }],
    },
    useDefaults: {
      oneOf: [{ type: "boolean" }, { type: "string", enum: ["array"] }],
    },
    // advanced options:
    next: {
      type: "boolean",
    },
    unevaluated: {
      type: "boolean",
    },
    dynamicRef: {
      type: "boolean",
    },
    jtd: {
      type: "boolean",
    },
    validateSchema: {
      $ref: "#/definitions/strictOption",
    },
    addUsedSchema: {
      type: "boolean",
    },
    inlineRefs: {
      oneOf: [{ type: "boolean" }, { type: "number" }],
    },
    passContext: {
      type: "boolean",
    },
    loopRequired: {
      type: "number",
    },
    loopEnum: {
      type: "number",
    },
    ownProperties: {
      type: "boolean",
    },
    multipleOfPrecision: {
      type: "number",
    },
    messages: {
      type: "boolean",
    },
    code: {
      $ref: "#/definitions/codeOption",
    },
  },
  definitions: {
    strictOption: {
      oneOf: [{ type: "boolean" }, { type: "string", enum: ["log"] }],
    },
    codeOption: {
      type: "object",
      properties: {
        es5: {
          type: "boolean",
        },
        lines: {
          type: "boolean",
        },
        optimize: {
          oneOf: [{ type: "boolean" }, { type: "number" }],
        },
        source: {
          type: "boolean",
        },
      },
    },
  },
}

@Eomm Eomm added the good first issue Good for newcomers label Nov 7, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
good first issue Good for newcomers
Projects
None yet
Development

No branches or pull requests

2 participants