Search code examples
javascriptjsonperformancev8

V8 Hidden Classes and JSON.parse() converting object property from string to Date


I have a REST endpoint that returns large array (100K+ elements) with objects that have properties that contain dates in ISO format (like 2021-08-08T10:48:39.637Z) and I need to parse them to Date type.

I currently have something like:

const res = await fetch(...);
const json = await res.json();
for (let x of json.arr) {
  x.d = new Date(x.d);
}

I'm worried that this might cause some unwanted slowness by messing with V8 Hidden Classes and also because of the type change (string => Date) for d property.

I read here that changing property type messes with V8 inner optimizations:

Changing the property or element type typically causes V8 to create a different HiddenClass which can lead to type pollution which prevents V8 from generating optimal code.

One alternative might be to use JSON.parse() with revival() param, that allows to parse values based on key name, but I'm not sure how the internals are handled with V8 in this and is there even a difference compared to what I'm doing currently.

  const json = JSON.parse(txt, (key, val) => {
    if (key === "d") {
      return new Date(val);
    }
    return val;
  });

Another approach might be to remap the objects returned from await res.json() like

const json = await res.json();
const objArr = json.map(x => ({ ...x, d: new Date(x.d) }));

With this approach I'm concerned about the overhead of cloning 100K+ objects and will they all have the same V8 Hidden Class?

I'm not concerned about JSON.parse() performance by itself, only about messing up V8 Hidden Classes or messing with some internal optimizations due to property type change to Date. It's a large array of objects and performance is very important for this WebApp, so I want to make sure I'm not making any huge mistakes.

What would be the most efficient way to parse Date types, taking into consideration the V8 optimzations?


Solution

  • (V8 developer here.)

    It's fine, just write code that makes sense and let the engine worry about making it fast. There's nothing wrong with your current approach.

    Also, if it did turn out that the most obvious way to write some code wasn't running as well as it could, then it'd be our job to fix that; we wouldn't want JavaScript developers to have to go through contortions to work around engine deficiencies.

    is there even a difference compared to what I'm doing currently

    Generally speaking, the only way to make sure which of two (or more) approaches is better, and whether there even is a difference, is to implement both and measure. When you do that, be sure to use realistic data, ideally your own full production app, or a snapshot/simulation of it. Reduced microbenchmarks with just a couple of lines are usually misleading (i.e.: what they appear to be telling you is unrelated to, and maybe even the opposite of, what effect you'll see in your full app), because dramatically simplifying the scenario usually changes the decisions that an engine will make under the hood. You may think "but in my full app, I won't see the impact of such a small detail" -- well, if that's the case, then that's your answer: it doesn't matter.