Object.observe polyfill (v14)

Revision 14 of this benchmark created by Misko Hevery on


Setup

function rndFieldName() {
      return 'a' + Math.floor(Math.random()*999).toString(16);
    }
    
    function createWatch1(last) {
      var field = rndFieldName();
      var obj = {};
      obj[field] = 1;
      return (last.next = {
        obj: obj,
        lastValue: 1,
        field: field,
        next: null
      });
    }
    function createWatch2(last) {
      var field0 = rndFieldName();
      var field1 = rndFieldName();
      var field2 = rndFieldName();
      var field3 = rndFieldName();
      var field4 = rndFieldName();
      var field5 = rndFieldName();
      var field6 = rndFieldName();
      var field7 = rndFieldName();
      var field8 = rndFieldName();
      var field9 = rndFieldName();
      var getter0 = new Function('s', 'return s.'+field0);
      var getter1 = new Function('s', 'return s.'+field1);
      var getter2 = new Function('s', 'return s.'+field2);
      var getter3 = new Function('s', 'return s.'+field3);
      var getter4 = new Function('s', 'return s.'+field4);
      var getter5 = new Function('s', 'return s.'+field5);
      var getter6 = new Function('s', 'return s.'+field6);
      var getter7 = new Function('s', 'return s.'+field7);
      var getter8 = new Function('s', 'return s.'+field8);
      var getter9 = new Function('s', 'return s.'+field9);
      var obj0 = {};
      var obj1 = {};
      var obj2 = {};
      var obj3 = {};
      var obj4 = {};
      var obj5 = {};
      var obj6 = {};
      var obj7 = {};
      var obj8 = {};
      var obj9 = {};
      obj0[field0] = 1;
      obj1[field1] = 1;
      obj2[field2] = 1;
      obj3[field3] = 1;
      obj4[field4] = 1;
      obj5[field5] = 1;
      obj6[field6] = 1;
      obj7[field7] = 1;
      obj8[field8] = 1;
      obj9[field9] = 1;
      return (last.next = {
        obj0: obj0, lastValue0: 1, field0: field0, getter0:getter0,
        obj1: obj1, lastValue1: 1, field1: field1, getter1:getter1,
        obj2: obj2, lastValue2: 1, field2: field2, getter2:getter2,
        obj3: obj3, lastValue3: 1, field3: field3, getter3:getter3,
        obj4: obj4, lastValue4: 1, field4: field4, getter4:getter4,
        obj5: obj5, lastValue5: 1, field5: field5, getter5:getter5,
        obj6: obj6, lastValue6: 1, field6: field6, getter6:getter6,
        obj7: obj7, lastValue7: 1, field7: field7, getter7:getter7,
        obj8: obj8, lastValue8: 1, field8: field8, getter8:getter8,
        obj9: obj9, lastValue9: 1, field9: field9, getter9:getter9,
        next: null
      });
    }
    function createWatch3(last) {
      var field = rndFieldName();
      var getter = new Function('s', 'return s.'+field);
      var obj = {};
      obj[field] = 1;
      return (last.next = {
        obj0: obj, lastValue0: 1, field0: field, getter0:getter,
        obj1: obj, lastValue1: 1, field1: field, getter1:getter,
        obj2: obj, lastValue2: 1, field2: field, getter2:getter,
        obj3: obj, lastValue3: 1, field3: field, getter3:getter,
        obj4: obj, lastValue4: 1, field4: field, getter4:getter,
        next: null
      });
    }
    var head1 = createWatch1({});
    var current = head1;
    for(var i = 1; i < 10000; i++) {
      current = createWatch1(current);
    }
    
    var head2 = createWatch2({});
    var current = head2;
    for(var i = 1; i < 1000; i++) {
      current = createWatch2(current);
    }
    
    var head4 = createWatch3({});
    var current = head4;
    for(var i = 1; i < 2000; i++) {
      current = createWatch2(current);
    }
    
    ///////////////////////////////////////
    function Watch1(previous) {
      if (previous) previous.next = this;
      this.field = rndFieldName();
      this.obj = {};
      this.lastValue = 1;
      this.getter = new Function('c', 'return c.' + this.field);
      this.obj[this.field] = this.lastValue;
      this.check = Watch1.prototype.check;
    }
    
    Watch1.prototype.check = function() {
      if (this.obj[this.field] !== this.lastValue) throw "DIRTY";
      return this.next;
    }
    
    var head3 = new Watch1();
    var current = head3;
    for(var i = 1; i < 10000; i++) {
      current = new Watch1(current);
    }
    
    ///////////////////////////////////////
    var size = 10000;
    var objs = new Array(size);
    var objFields = new Array(size);
    var lastValues = new Array(size);
    for(var i = 0; i < size; i++) {
      var obj = objs[i] = {};
      objFields[i] = 'a' + Math.floor(Math.random()*999).toString(16);
      lastValues[i] = obj[objFields[i]] = 1;
    }

Test runner

Ready to run.

Testing in
TestOps/sec
dirtyCheck1
var current = head1;
while(current) {
  if (current.obj[current.field] !== current.lastValue) {
     throw "DIRTY";
  }
  current = current.next;
}
 
ready
dirtyCheck2
var c = head2;
while(c) {
  if (c.obj0[c.field0] !== c.lastValue0) throw "X0";
  if (c.obj1[c.field1] !== c.lastValue1) throw "X1";
  if (c.obj2[c.field2] !== c.lastValue2) throw "X2";
  if (c.obj3[c.field3] !== c.lastValue3) throw "X3";
  if (c.obj4[c.field4] !== c.lastValue4) throw "X4";
  if (c.obj5[c.field5] !== c.lastValue5) throw "X5";
  if (c.obj6[c.field6] !== c.lastValue6) throw "X6";
  if (c.obj7[c.field7] !== c.lastValue7) throw "X7";
  if (c.obj8[c.field8] !== c.lastValue8) throw "X8";
  if (c.obj9[c.field9] !== c.lastValue9) throw "X9";
  c = c.next;
}
 
ready
dirtyCheck3
for(var i=0, ii=objs.length; i<ii; i++) {
  if (objs[i][objFields[i]] !== lastValues[i]) throw 'x';
}
ready
unrolled reflect
for(var i=0, ii=objs.length; i<ii; i=i+10) {
  if (objs[i][objFields[i]] !== lastValues[i]) throw 'x';
  if (objs[i+1][objFields[i+1]] !== lastValues[i+1]) throw 'x';
  if (objs[i+2][objFields[i+2]] !== lastValues[i+2]) throw 'x';
  if (objs[i+3][objFields[i+3]] !== lastValues[i+3]) throw 'x';
  if (objs[i+4][objFields[i+4]] !== lastValues[i+4]) throw 'x';
  if (objs[i+5][objFields[i+5]] !== lastValues[i+5]) throw 'x';
  if (objs[i+6][objFields[i+6]] !== lastValues[i+6]) throw 'x';
  if (objs[i+7][objFields[i+7]] !== lastValues[i+7]) throw 'x';
  if (objs[i+8][objFields[i+8]] !== lastValues[i+8]) throw 'x';
  if (objs[i+9][objFields[i+9]] !== lastValues[i+9]) throw 'x';
}
ready
function getter
var c = head2;
while(c) {
  if (c.getter0(c.obj0) !== c.lastValue0) throw "X";
  if (c.getter1(c.obj1) !== c.lastValue1) throw "X";
  if (c.getter2(c.obj2) !== c.lastValue2) throw "X";
  if (c.getter3(c.obj3) !== c.lastValue3) throw "X";
  if (c.getter4(c.obj4) !== c.lastValue4) throw "X";
  if (c.getter5(c.obj5) !== c.lastValue5) throw "X";
  if (c.getter6(c.obj6) !== c.lastValue6) throw "X";
  if (c.getter7(c.obj7) !== c.lastValue7) throw "X";
  if (c.getter8(c.obj8) !== c.lastValue8) throw "X";
  if (c.getter9(c.obj9) !== c.lastValue9) throw "X";
  c = c.next;
}
 
ready
Watch class
var current = head3;
while(current) {
  if (current.obj[current.field] !== current.lastValue) {
     throw "DIRTY";
  }
  current = current.next;
}
 
ready
Watch Class method
var current = head3;
while(current = current.check());
 
ready
Watch class getter
var current = head3;
while(current) {
  if (current.getter(current.obj) !== current.lastValue) throw "DIRTY";
  current = current.next;
}
 
ready
dirtyCheck1 if
var c = head4;
while(c) {
  if (c.getter0(c.obj0) !== c.lastValue0) throw "X";
  if (c.getter1(c.obj1) !== c.lastValue1) throw "X";
  if (c.getter2(c.obj2) !== c.lastValue2) throw "X";
  if (c.getter3(c.obj3) !== c.lastValue3) throw "X";
  if (c.getter4(c.obj4) !== c.lastValue4) throw "X";
  c = c.next;
}
 
ready

Revisions

You can edit these tests or add more tests to this page by appending /edit to the URL.

  • Revision 1: published by Misko Hevery on
  • Revision 2: published by Misko Hevery on
  • Revision 3: published by Misko Hevery on
  • Revision 4: published by Misko Hevery on
  • Revision 5: published by Misko Hevery on
  • Revision 6: published by Misko Hevery on
  • Revision 7: published by Misko Hevery on
  • Revision 8: published by Misko Hevery on
  • Revision 9: published by Misko Hevery on
  • Revision 10: published by Misko Hevery on
  • Revision 11: published by Misko Hevery on
  • Revision 12: published by Misko Hevery on
  • Revision 13: published by Misko Hevery on
  • Revision 14: published by Misko Hevery on