AngularJS $parse getter

Benchmark created by Igor Minar on


Setup

function getterFn(path, csp) {
      var pathKeys = path.split('.'),
          fn;
    
      if (csp) {
        fn = function(scope, locals) {
          var pathVal = (locals && locals.hasOwnProperty(pathKeys[0])) ? locals : scope,
              promise, i, ii, key;
    
          for(i = 0, ii = pathKeys.length; i < ii; i++) {
            if (!pathVal) break;
            key = pathKeys[i];
            pathVal = pathVal[key];
    
            if (pathVal && pathVal.then) {
              if (!("$$v" in pathVal)) {
                promise = pathVal;
                promise.$$v = undefined;
                promise.then(function(val) { promise.$$v = val; });
              }
              pathVal = pathVal.$$v;
            }
          }
    
          return pathVal;
        }
    
      } else {
        var code = 'var l, fn, p;\n';
        forEach(pathKeys, function(key, index) {
          code += 'if(!s) return s;\n' +
                  'l=s;\n' +
                  's='+ (index
                          // we simply dereference 's' on any .dot notation
                          ? 's'
                          // but if we are first then we check locals first, and if so read it first
                          : '((k&&k.hasOwnProperty("' + key + '"))?k:s)') + '["' + key + '"]' + ';\n' +
                  'if (s && s.then) {\n' +
                    ' if (!("$$v" in s)) {\n' +
                      ' p=s;\n' +
                      ' p.$$v = undefined;\n' +
                      ' p.then(function(v) {p.$$v=v;});\n' +
                      '}\n' +
                    ' s=s.$$v\n' +
                  '}\n';
        });
        code += 'return s;';
        fn = Function('s', 'k', code); // s=scope, k=locals
        fn.toString = function() { return code; };
      }
    
      return fn;
    }
    
    
    getterEvil = getterFn('a.b.c.d.e.f');
    getterGood = getterFn('a.b.c.d.e.f', true);
    obj = {a: { b: { c: { d: { e: { f: 23 } } } } } };
    locals = {a: { b: { c: { d: { e: { f: 23 } } } } } };
    
    
    function forEach(array, iterator) {
      for(var i=0, ii=array.length; i < ii; i++) {
        iterator(array[i], i);
      }
    }

Test runner

Ready to run.

Testing in
TestOps/sec
Evil
getterEvil(obj);
ready
Evil + Locals
getterEvil(obj, locals);
ready
Good
getterGood(obj);
ready
Good + Locals
getterGood(obj, locals);
ready

Revisions

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

  • Revision 1: published by Igor Minar on
  • Revision 2: published by Igor Minar on
  • Revision 3: published by Igor Minar on
  • Revision 4: published by Igor Minar on
  • Revision 6: published by Karl Seamon on