Skip to content

Instantly share code, notes, and snippets.

@burnpiro
Created August 1, 2019 13:14
Show Gist options
  • Save burnpiro/03ebfca377bc037cda840757cddc528d to your computer and use it in GitHub Desktop.
Save burnpiro/03ebfca377bc037cda840757cddc528d to your computer and use it in GitHub Desktop.
Spread VS JSON.parse performance in function optimisation

Spread vs JSON.parse speed when calling simple function

const N = 100000;

function test(obj) {
  var result = obj.a + obj.b;
  return result;
}
function test2(obj) {
  var result = obj.a + obj.b;
  return result;
}

const objToCopy1 = { a: 1, b: 2 };
const objToCopy2 = { a: 1, b: 2 };
const objToCopy3 = { a: 1, b: 2 };
const objToCopy4 = { a: 1, b: 2 };
const objToCopy5 = { a: 1, b: 2 };
const startParse = Date.now();
for (let i = 0; i < N; ++i) {
	test(JSON.parse(JSON.stringify(objToCopy1)));
	test(JSON.parse(JSON.stringify(objToCopy2)));
	test(JSON.parse(JSON.stringify(objToCopy3)));
	test(JSON.parse(JSON.stringify(objToCopy4)));
	test(JSON.parse(JSON.stringify(objToCopy5)));
}
console.log("test with PARSE:", Date.now() - startParse, "ms.");

const startSpread = Date.now();
for (let i = 0; i < N; ++i) {
	test2({...objToCopy1});
	test2({...objToCopy2});
	test2({...objToCopy3});
	test2({...objToCopy4});
	test2({...objToCopy5});
}
console.log("test with spread:", Date.now() - startSpread, "ms.");

Result

test with PARSE: 263 ms.
test with spread: 12 ms.

When calling complex function (many operations inside):

const N = 10000;

function test(obj) {
  let result = 0;
  for (let i = 0; i < N; i++) {
  	result += obj.a + obj.b
  }
  return result;
}
function test2(obj) {
  let result = 0;
  for (let i = 0; i < N; i++) {
  	result += obj.a + obj.b
  }
  return result;
}

const objToCopy1 = { a: 1, b: 2 };
const objToCopy2 = { a: 1, b: 2 };
const objToCopy3 = { a: 1, b: 2 };
const objToCopy4 = { a: 1, b: 2 };
const objToCopy5 = { a: 1, b: 2 };
const startParse = Date.now();
for (let i = 0; i < N; ++i) {
	test(JSON.parse(JSON.stringify(objToCopy1)));
	test(JSON.parse(JSON.stringify(objToCopy2)));
	test(JSON.parse(JSON.stringify(objToCopy3)));
	test(JSON.parse(JSON.stringify(objToCopy4)));
	test(JSON.parse(JSON.stringify(objToCopy5)));
}
console.log("test with PARSE:", Date.now() - startParse, "ms.");

const startSpread = Date.now();
for (let i = 0; i < N; ++i) {
	test2({...objToCopy1});
	test2({...objToCopy2});
	test2({...objToCopy3});
	test2({...objToCopy4});
	test2({...objToCopy5});
}
console.log("test with spread:", Date.now() - startSpread, "ms.");

Result:

test with PARSE: 288 ms.
test with spread: 4054 ms.

Reason? Function deoptimisation when spreading objects:

// IC change with spread
ℹ	40%	4	P → P
ℹ	20%	2	. → 1
ℹ	20%	2	1 → P
ℹ	20%	2	P → N
// IC change with JSON.parse
100%	2	. → 1
@mdbetancourt
Copy link

i have a question why if %HaveSameMap({...objToCopy1}, {...objToCopy2}) is true, test2 is deoptimized?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment