1
\$\begingroup\$

I have function decodeVals in NodeJS that decodes all of the values of the given object from Base64 to ASCII. This is achieved by traversing the values of said object then converting each element one at a time via a function call to the "homemade" atob function.

Though the results are fast on objects I've tested - which are relatively small - I imagine this could be inefficient for much larger objects.


Does anyone know of a more efficient/less expensive way of achieving this?

const atob = (str) => Buffer.from(str, 'base64').toString();


// Decoder Function
function decodeVals(obj) {
  for (let [key, value] of Object.entries(obj)) {
    if (!Array.isArray(value)) {
      obj[key] = atob(value);
    } else {
      for (let arrayElement of value) {
        obj[key][obj[key].indexOf(arrayElement)] = atob(arrayElement);
      }
    }
  }
  return obj;
}


const testObj = {  
  correct_answer: 'VHJlbnQgUmV6bm9y',      
  incorrect_answers: ['TWFyaWx5biBNYW5zb24=', 'Um9iaW4gRmluY2s=', 'Sm9zaCBIb21tZQ=='],
};

const res = decodeVals(testObj);

console.log(res);
/*
 {
  correct_answer: 'Trent Reznor',
  incorrect_answers: ['Marilyn Manson', 'Robin Finck', 'Josh Homme']
 }
*/
\$\endgroup\$
3
  • 3
    \$\begingroup\$ You can change inner loop to avoid calling indexOf (which has a loop over all elements inside) - like using for..in instead if for..of. And add motivation for such strange form of data handling. Are you trying to obfuscate data in a config file/database? \$\endgroup\$ Commented Jul 6, 2021 at 4:42
  • \$\begingroup\$ Data from an API is recieved similar to testObj, with the values being in base64. The goal is to decode given JSON from said API \$\endgroup\$
    – Elitezen
    Commented Jul 6, 2021 at 11:55
  • \$\begingroup\$ I see what you mean about the inner-loop and now see how that can be beneficial! \$\endgroup\$
    – Elitezen
    Commented Jul 6, 2021 at 11:58

1 Answer 1

2
\$\begingroup\$

I would suggest breaking out decode into dedicated functions. This way, the code is much more readable, and you can easily find which pieces need to be optimized.

For instance, in the following snippet, I split out decoding into types. You can clearly see that decodeObject may not be the most optimized, as its reduce operation does some copying, which can be replaced with a different implementation without affecting how the others work.

const atob = (str) => Buffer.from(str, 'base64').toString();

const decodeObject = obj => {
  return Object
    .entries(obj)
    .reduce((c, ([key, value])) => ({ ...c, [key]: decode(value) }), {})
}

const decodeArray = array => {
  return array.map(v => decode(v))
}

const decodeString = str => atob(str)

const decode = value => {
  return value == null ? null // weed out null and undefined early
    : typeof value === string ? decodeString(value)
    : typeof value === 'object' ? decodeObject(value)
    : typeof value === 'array' ? decodeArray(value)
    : value // Dunno what to do, leave it alone.
}

I also advice against destructively modifying your source object. You never know what other piece of code might be holding a reference to it, which might break because it was expecting a different value.

And since this is Node.js, you can always split the task across threads. I'm assuming you'll be working with an array of these kinds of objects. You can split up the array and have a different thread work on a chunk of the array. Maximize the use of the hardware.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.