Skip to content

Instantly share code, notes, and snippets.

@robpalme
Last active January 17, 2022 16:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save robpalme/a9ff3e4764b764d7dc24743816d8a624 to your computer and use it in GitHub Desktop.
Save robpalme/a9ff3e4764b764d7dc24743816d8a624 to your computer and use it in GitHub Desktop.
Class Field initialization time
class Classic_Constructor_Assignments {
constructor() {
this.verification=1;
this._00=1; this._01=1; this._02=1; this._03=1; this._04=1; this._05=1; this._06=1; this._07=1; this._08=1; this._09=1;
this._10=1; this._11=1; this._12=1; this._13=1; this._14=1; this._15=1; this._16=1; this._17=1; this._18=1; this._19=1;
this._20=1; this._21=1; this._22=1; this._23=1; this._24=1; this._25=1; this._26=1; this._27=1; this._28=1; this._29=1;
this._30=1; this._31=1; this._32=1; this._33=1; this._34=1; this._35=1; this._36=1; this._37=1; this._38=1; this._39=1;
this._40=1; this._41=1; this._42=1; this._43=1; this._44=1; this._45=1; this._46=1; this._47=1; this._48=1; this._49=1;
this._50=1; this._51=1; this._52=1; this._53=1; this._54=1; this._55=1; this._56=1; this._57=1; this._58=1; this._59=1;
this._60=1; this._61=1; this._62=1; this._63=1; this._64=1; this._65=1; this._66=1; this._67=1; this._68=1; this._69=1;
this._70=1; this._71=1; this._72=1; this._73=1; this._74=1; this._75=1; this._76=1; this._77=1; this._78=1; this._79=1;
this._80=1; this._81=1; this._82=1; this._83=1; this._84=1; this._85=1; this._86=1; this._87=1; this._88=1; this._89=1;
this._90=1; this._91=1; this._92=1; this._93=1; this._94=1; this._95=1; this._96=1; this._97=1; this._98=1; this._99=1;
}
}
class ES2022_Public_Fields {
verification=1;
_00=1; _01=1; _02=1; _03=1; _04=1; _05=1; _06=1; _07=1; _08=1; _09=1;
_10=1; _11=1; _12=1; _13=1; _14=1; _15=1; _16=1; _17=1; _18=1; _19=1;
_20=1; _21=1; _22=1; _23=1; _24=1; _25=1; _26=1; _27=1; _28=1; _29=1;
_30=1; _31=1; _32=1; _33=1; _34=1; _35=1; _36=1; _37=1; _38=1; _39=1;
_40=1; _41=1; _42=1; _43=1; _44=1; _45=1; _46=1; _47=1; _48=1; _49=1;
_50=1; _51=1; _52=1; _53=1; _54=1; _55=1; _56=1; _57=1; _58=1; _59=1;
_60=1; _61=1; _62=1; _63=1; _64=1; _65=1; _66=1; _67=1; _68=1; _69=1;
_70=1; _71=1; _72=1; _73=1; _74=1; _75=1; _76=1; _77=1; _78=1; _79=1;
_80=1; _81=1; _82=1; _83=1; _84=1; _85=1; _86=1; _87=1; _88=1; _89=1;
_90=1; _91=1; _92=1; _93=1; _94=1; _95=1; _96=1; _97=1; _98=1; _99=1;
}
class ES2022_Private_Fields {
verification=1;
#_00=1; #_01=1; #_02=1; #_03=1; #_04=1; #_05=1; #_06=1; #_07=1; #_08=1; #_09=1;
#_10=1; #_11=1; #_12=1; #_13=1; #_14=1; #_15=1; #_16=1; #_17=1; #_18=1; #_19=1;
#_20=1; #_21=1; #_22=1; #_23=1; #_24=1; #_25=1; #_26=1; #_27=1; #_28=1; #_29=1;
#_30=1; #_31=1; #_32=1; #_33=1; #_34=1; #_35=1; #_36=1; #_37=1; #_38=1; #_39=1;
#_40=1; #_41=1; #_42=1; #_43=1; #_44=1; #_45=1; #_46=1; #_47=1; #_48=1; #_49=1;
#_50=1; #_51=1; #_52=1; #_53=1; #_54=1; #_55=1; #_56=1; #_57=1; #_58=1; #_59=1;
#_60=1; #_61=1; #_62=1; #_63=1; #_64=1; #_65=1; #_66=1; #_67=1; #_68=1; #_69=1;
#_70=1; #_71=1; #_72=1; #_73=1; #_74=1; #_75=1; #_76=1; #_77=1; #_78=1; #_79=1;
#_80=1; #_81=1; #_82=1; #_83=1; #_84=1; #_85=1; #_86=1; #_87=1; #_88=1; #_89=1;
#_90=1; #_91=1; #_92=1; #_93=1; #_94=1; #_95=1; #_96=1; #_97=1; #_98=1; #_99=1;
}
// Benchmarking
const ITERATIONS = 100_000;
console.log(`Time to construct ${ITERATIONS} instances that each initialize 100 fields using different techniques.`);
function bench (testClass) {
var start = performance.now();
var acc = 0;
for (var i=0; i<ITERATIONS; i++) {
const instance = new testClass()
acc += instance.verification;
}
var duration = performance.now() - start;
console.log(`${testClass.name} took ${Math.ceil(duration)}ms (honest:${acc===ITERATIONS})`);
}
bench(Classic_Constructor_Assignments);
bench(ES2022_Public_Fields);
bench(ES2022_Private_Fields);
@robpalme
Copy link
Author

robpalme commented Jul 6, 2021

Rough findings (as of July 2021) compared to the baseline constructor initialization:

  • V8 Canary is 100x slower at fields (both public and private) than constructor init ☹
  • On M1 Mac, JSC public fields are 10x slower than constructor init
  • On M1 Mac, JSC private fields achieve parity with constructor init 😀

@robpalme
Copy link
Author

robpalme commented Oct 19, 2021

Latest Results (as of October 2021)

Time spent creating 100k instances that each initialize 100 fields. Measured on Window 10.

Chrome 97.0.4674.0 includes this optimization.

Field Initialization Technique Chrome 94.0.4606.81 Chrome 97.0.4674.0
Classic Constructor Assignments 27ms 26ms
Public Fields 1415ms 20ms
Private Fields 1339ms 18ms

@robpalme
Copy link
Author

Latest Results (as of October 2021)

Time spent creating 100k instances that each initialize 100 fields.

Measured on Macbook Air (M1, 2020) 8GB running MacOS Monterey 12.0.1.

Field Initialization Technique Safari Tech Preview
134 (Safari 15.4, WebKit 17613.1.6.1)
Chrome Canary
97.0.4674.0
Firefox Nightly
95.0a1 (2021-10-28)
Classic Constructor Assignments 38ms 23ms 53ms
Public Fields 462ms 18ms 47ms
Private Fields 33ms 16ms 54ms

@robpalme
Copy link
Author

robpalme commented Jan 17, 2022

Latest Results (as of January 2022)

Time spent creating 100k instances that each initialize 100 fields.

Measured on Macbook Air (M1, 2020) 8GB running MacOS Monterey 12.1

Safari Tech Preview 137 includes this optimization

Field Initialization Technique Safari Tech Preview
137 (Safari 15.4, WebKit 17613.1.11.8)
Chrome Canary
99.0.4828.0 arm64
Firefox Nightly
98.0a1 (2022-01-17) 64-bit
Classic Constructor Assignments 29ms 25ms 46ms
Public Fields 28ms 16ms 47ms
Private Fields 28ms 14ms 55ms

All significant performance issues are now resolved 🎉

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