最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Object descriptor gettersetter performance in recent ChromeV8 versions - Stack Overflow

programmeradmin1浏览0评论

Given

var obj = {};

var _a = 1;

obj._a = 1;

obj.aGetter = function() {
  return _a;
}

obj.aSetter = function(val) {
  _a = val;
}

Object.defineProperty(obj, 'a', {
  enumerable: true,
  get: function () {
    return _a;  
  },
  set: function(val) {
    _a = val;
  }     
});

using getter/setter functions

obj.aSetter(2);
obj.aGetter();

will have some decrease in Chrome/V8 performance (~3x) when pared to direct property access:

obj._a = 2;
obj._a;

This is be understandable. And using descriptor getter/setter

obj.a = 2;
obj.a;

will cause ~30x decrease in Chrome (41 to latest) performance - almost as slow as Proxy. While Firefox and older Chrome versions use descriptor getter/setter with no significant performance penalty.

What is the exact problem with descriptor getter/setter performance in recent Chrome/V8 versions? Is it a known issue that can be monitored?

The measurements were done with Benchmark.js (jsPerf engine). I'm unable to provide a link to jsPerf test to visualize the difference because jsPerf has been seriously screwed up with its anti-DDoS measures, but I'm sure there are existing ones that can prove a point.

Given

var obj = {};

var _a = 1;

obj._a = 1;

obj.aGetter = function() {
  return _a;
}

obj.aSetter = function(val) {
  _a = val;
}

Object.defineProperty(obj, 'a', {
  enumerable: true,
  get: function () {
    return _a;  
  },
  set: function(val) {
    _a = val;
  }     
});

using getter/setter functions

obj.aSetter(2);
obj.aGetter();

will have some decrease in Chrome/V8 performance (~3x) when pared to direct property access:

obj._a = 2;
obj._a;

This is be understandable. And using descriptor getter/setter

obj.a = 2;
obj.a;

will cause ~30x decrease in Chrome (41 to latest) performance - almost as slow as Proxy. While Firefox and older Chrome versions use descriptor getter/setter with no significant performance penalty.

What is the exact problem with descriptor getter/setter performance in recent Chrome/V8 versions? Is it a known issue that can be monitored?

The measurements were done with Benchmark.js (jsPerf engine). I'm unable to provide a link to jsPerf test to visualize the difference because jsPerf has been seriously screwed up with its anti-DDoS measures, but I'm sure there are existing ones that can prove a point.

Share Improve this question asked Mar 31, 2016 at 15:59 Estus FlaskEstus Flask 223k78 gold badges471 silver badges608 bronze badges 8
  • 1 How do the old Chrome versions pare to the new ones in the direct access - have they gotten faster, or accessor performance really decreased? – Bergi Commented Mar 31, 2016 at 16:33
  • Afaik, getters/setters are not optimised well in V8. – Bergi Commented Mar 31, 2016 at 16:34
  • @Bergi Descriptor accessors seem to be optimized quite well in GC <= 39 (object properties don't perform as good as in FF but anyway). But something changed in 41 (haven't got GC 40 to check it), that's the most ridiculous part. – Estus Flask Commented Mar 31, 2016 at 17:01
  • 3 @estus the mit that caused regression is codereview.chromium/714883003, it removed the code that was used to recover from transition clash. in general in V8 it is a good idea to put getters/setters on the prototype - not on to the immediate object to avoid this sort of situations. – Vyacheslav Egorov Commented Apr 1, 2016 at 21:20
  • 2 @VyacheslavEgorov Good hint, the optimizations are indeed there when descriptor is defined on the prototype.Thanks for the research work, you can submit it as an answer if you wish to. – Estus Flask Commented Apr 1, 2016 at 22:27
 |  Show 3 more ments

1 Answer 1

Reset to default 15

The changes in performance are relevant to this Chromium issue (credits go to @VyacheslavEgorov).

To avoid performance issues, a prototype should be used instead. This is one of few reasons why singleton classes may be used to instantiate an object once.

With ES5:

var _a = 1;

function Obj() {}

Object.defineProperty(Obj.prototype, 'a', {
  enumerable: true,
  get: function () {
    return _a;  
  },
  set: function(val) {
    _a = val;
  }     
});

var obj = new Obj();
// or
var obj = Object.create(Obj.prototype);

Or with ES6 syntactic sugar:

class Obj {
  constructor() {
    this._a = 1;
  }

  get a() {
    return this._a;
  }

  set a(val) {
    this._a = val;
  }     
}

let obj = new Obj();
发布评论

评论列表(0)

  1. 暂无评论