In JavaScript development, we often need to use simple objects, such as passing simple objects as configuration to other class libraries.

But did you know that it’s faster for JavaScript to write configurations as JSON strings than it is to write simple objects?

The simple object

What is a simple object?

In JavaScript, we can define a simple object directly with a pair of curly braces, such as:

const obj = {
  foo: 'hello world'.bar: {
    baz: ['1'.20.0x012c.4000n, 50_000],}};Copy the code

This produces a simple object and takes it as the value of the constant obj. This simple object contains two fields: foo, which is a string, and bar, which is another simple object that contains the baz field, which is an array, Contains the string ‘1’, the decimal number 20, the hexadecimal number 300, the BigInt number 4000, and the underlined delimiter number 50000.

Now, as you might have noticed, this is a simple object, but it’s not simple, because there are so many different ways to write numbers.

Simple objects in JavaScript

JavaScript is the language used to interpret execution. Code is downloaded to the browser as plain text (node.js does not require this step), and then interpreted by the interpreter and translated into machine instructions. In the process of code interpretation, due to the need to take into account the various syntax of the code, it needs a lot of time to judge, and because the code is usually explained from start to end, character by character, it even needs to be backtracked a lot of times.

For example, we now have code like this:

const value = 'any value';
constObj = ({value ▓ ▓ ▓ ▓ ▓ ▓ ▓ ▓ ▓ ▓ ▓ ▓ ▓ ▓ ▓ ▓ ▓Copy the code

What does the value after obj stand for when the JS interpreter interprets this? I’m not sure, it depends on the code, if it looks like this:

const value = 'any value';
const obj = ({ value: 1▓ ▓ ▓ ▓ ▓ ▓ ▓ ▓Copy the code

So the value after obj is independent of the value constant above.

But if the back looks like this:

const value = 'any value';
constObj = ({value}Copy the code

Obj = value; obj = value; ? Not really, but it depends on more code. If followed by a semicolon:

const value = 'any value';
const obj = ({ value });
Copy the code

{value: ‘any value’} obj is a simple object {value: ‘any value’}.

However, if the following code looks like this:

const value = 'any value';
const obj = ({ value }).value;
Copy the code

The value after obj is the value constant, but obj is the string ‘any value’.

Or, if the following code looks like this:

const value = 'any value';
const obj = ({ value }) = > value;
Copy the code

The meaning of the code is completely different. Obj becomes an arrow function, followed by value as the deconstructed parameter, followed by value as the return value of the arrow function.

As you can see, if you use simple objects in your code, the JavaScript interpreter needs to make a lot of judgment when interpreting the syntax, and even interpret the meaning of the previous code content differently based on the content of the following code.

JSON strings are different.

Use JSON to generate simple objects

So, what is JSON?

JSON is short for JavaScript Object Notation, which is essentially a string representation of a simple JavaScript Object encoded in a format with very little syntax and a very simple syntax structure. JSON strings contain very few data types because of their simple syntax, but this is sufficient for most scenarios.

JSON, with its simple syntax, in carries on the explanation, can fully explain, in accordance with the order of the once upon a time after each character semantics is determined according to the above, not because of followed by the contents of different show different meanings, so in the syntax parsing, only need a stack structure, and then used to order after parsing, There will be no backtracking. And because JSON has no functions, no object deconstruction, no variables, nothing but {}, [], “”, and certain symbols, and simple data types like Object, array, String, number, Boolean, and NULL, And the writing method is relatively simple and single, so the number of judgments can be greatly reduced when parsing.

JSON is therefore much simpler and more efficient to interpret than JavaScript code.

In JavaScript, the json.parse function is provided in advance, which takes a JSON string as an argument and returns the result interpreted by the JSON string.

Since JSON can be interpreted much faster than JavaScript code, and json.parse is a built-in function, JSON strings are interpreted by C/C++ code inside the JavaScript interpreter. And skip the JavaScript syntax interpreter part directly, generating and returning references to JavaScript objects directly inside the interpreter.

Parse (‘, which tells you that a string is followed by a string, and works its way back to the end of the string. There is no complicated syntax (except for the ${} contained in the backquote string), but only the escape character \. The resulting string is then passed to the json.parse function for processing.

Therefore, this process is much faster than trying to interpret a JavaScript object directly (how much faster depends on how optimized the different JavaScript interpreters are, of course).

Analytical velocity comparison

Of course, all of the above has been limited to “theory” so far, and reality may be somewhat different from theory, for the sake of scientific rigor. We need to do some comparative experiments to verify this conclusion.

First, the test platform was Windows 10 1909 Sandbox, I7-9700K, Google Chrome 79.0.3945.88 (64-bit), Mozilla Firefox 71.0 (64-bit), Node.js 13.5.0 (64-bit).

⚠ Note: in the following test code, a load. Js is used to dynamically reference two JS files to be tested. Timing code such as console.time cannot be placed with the code under test because some JS engines (Firefox and Node.js) pre-process the JS code before executing it, and the results will be inaccurate.

Test code:

// JS.js
const use = (a)= > {};
let times = 10_0000;
while (times--) {
  use({string:'string'.number:1.array: ['string'.1].object: {Key1:'a'.Key2:'b'}});
}

// JSON.js
const use = (a)= > {};
let times = 10_0000;
while (times--) {
  use(JSON.parse('{"string":"string","number":1,"array":["string",1],"object":{"Key1":"a","Key2":"b"}}'));
}

// load.js
(async() = > {console.time('JS');
  await import('./JS.mjs');
  console.timeEnd('JS');
  console.time('JSON');
  await import('./JSON.mjs');
  console.timeEnd('JSON'); }) ();Copy the code

Well, it doesn’t seem to be a problem, so let’s try it out (the following data are averages of 10 tests) :

Chrome Firefox Node.JS
JS 19.6355 ms 413.2 ms 12.0093 ms
JSON 143.4788 ms 662 ms 105.9769 ms

Emmmmmm…

What’s wrong with the style? Shouldn’t JSON theoretically be faster than JS? Why is JSON so much slower than JS?

In fact, there is a problem with the testing method here!!

To recap, the fundamental reason JSON is faster than JS is because JSON parses faster than JS!

So when is the code parsed?

In fact, the above code, the JS version only interprets the simple objects in the middle during the first loop, after which the machine code is generated and no further interpretation is required.

Parse takes a string, but since it involves a json. parse function call, the json. parse function accepts a string, Json.parse reparses the string on each call, even if it is the same string.

Thus, the JSON version here actually forces the JavaScript engine to interpret the code 100,000 times, whereas the JS version interprets it only once. So the result will be JSON is many times slower than JS!

True · analytic speed comparison

So, how do we test JSON to prove that it is faster than JS?

It’s as simple as making sure that JSON and JS are interpreted the same number of times, or that they are interpreted only once.

The first option

Parse is a built-in JavaScript function like Json. parse. However, complete JavaScript code can be written in Eval. So Eval is still using a JS interpreter, not a JSON interpreter like json.parse.

Test code:

// JS.js
const use = (a)= > {};
let times = 10_0000;
while (times--) {
  use(eval(`({string:'string',number:1,array:['string',1],object:{Key1:'a',Key2:'b'}})`));
}

// JSON.js
const use = (a)= > {};
let times = 10_0000;
while (times--) {
  use(eval(`JSON.parse('{"string":"string","number":1,"array":["string",1],"object":{"Key1":"a","Key2":"b"}}')`));
}

// load.js
(async() = > {console.time('JS');
  await import('./JS.mjs');
  console.timeEnd('JS');
  console.time('JSON');
  await import('./JSON.mjs');
  console.timeEnd('JSON'); }) ();Copy the code

⚠ Note: the code using Eval here is very bad, JavaScript has to create 100,000 objects and then do garbage collection, the garbage collection takes the browser a long time to get stuck, and the final print takes much less time than the wait.

Well, it doesn’t seem to be a problem, so let’s try it out (the following data are averages of 10 tests) :

Chrome Firefox Node.JS
JS 4237.9201 ms 5815 ms 113.056 ms
JSON 4703.9819 ms 16244 ms 135.533 ms

emmmmmmmm……

Both are time-consuming, but overall JSON is still slower than JS, why?

In fact, this is because the simple object generated here is so “simple” that it is too short to be able to distinguish between the two.

But even if it doesn’t close the gap, JSON shouldn’t be slower than JS, right?

In fact, this approach forces both to parse the same number of times, but it is unfair to JSON because eval needs to parse the json.parse function call itself before the JSON version can parse, and the function call has a context-switching time overhead.

As a result, the increased parsing speed of JSON does not compensate for the overhead of json.parse function calls when the LENGTH of JSON is short, and as a result, the JSON version is slower than the JS version.

So, to measure the true parsing speed of JSON versus native JS, we’ll use the second solution:

Second option

In order for JSON and JS to be interpreted only once, our code has to be a layer of simple object creation.

Today’s computers are so fast that you can only see a significant time difference when you generate a large enough file.

Parse to get a large enough file, I took a 1.8 MB JSON file and passed it to json. parse as a simple JS object.

Test code (the JSON part of the code has been omitted) :

// JS.js
const use = (a)= > {};
console.time('JS'); use({... });console.timeEnd('JS');

// JSON.js
const use = (a)= > {};
console.time('JSON');
use(JSON.parse('{... } '));
console.timeEnd('JSON');


// JS.js
const use = (a)= >{}; use({... });// JSON.js
const use = (a)= > {};
let = times = 10_0000;
use(JSON.parse('{... } '));

// load.js
(async() = > {console.time('JS');
  await import('./JS.mjs');
  console.timeEnd('JS');
  console.time('JSON');
  await import('./JSON.mjs');
  console.timeEnd('JSON'); }) ();Copy the code

Test results (the following data are averages after 10 tests) :

Chrome Firefox Node.JS
JS 157.7056 ms 122.5 ms 108.6904 ms
JSON 87.2692 ms 77.4 ms 57.665 ms

Parse (‘{… } ‘); Than {… }; Quick, is it necessary to write your code in JSON form in everyday development?

Needless to say, should also know, should not!

If you write your code as a JSON string, it’s not only hard to read, In addition, some JavaScript codes cannot be directly represented by JSON (for example, undefined, Symbol and BigInt in JavaScript basic data types cannot be accurately represented as JSON). In most cases, The speed increase is not significant (0.01s is not much faster than 0.07s), so the benefit is not significant.

However, for projects of large front-end rendering types, most Web frameworks will have a lot of configuration code, which is usually string, number, Boolean, and other basic types, and can be very large, even a few MB or tens of MB. For large code like this, optimization of JSON strings is obvious.

However, these large projects usually use tools such as Webpack and Rollup for project processing. For such optimization operations, these packaging tools should be carried out

PS: Webpack included this optimization in the submission on July 2nd of this year, details: github.com/webpack/web…