Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How to use JSON.stringify replace to await Promise values?

I have a JSON object I want to stringify. Some of the values in this object are Promises.

How can I use the replacer parameter in JSON.stringify() to pass the result of the Promise, instead of the promise itself?

To give a clear example of what I mean, let’s assume the following object:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

const data = {
    foo: "foo",
    get bar() {
        return Promise.resolve('bar')
    },
    get baz() {
        return 'baz'
    },
}

If I call JSON.stringify(data), the result is:

{"foo":"foo","bar":{},"baz":"baz"}

But I want "bar" to be bar (similar to the result of "baz").

A naive attempt, using a replacer with async / await, doesn’t work:

const data = {
  foo: "foo",
  get bar() {
    return Promise.resolve('bar')
  },
  get baz() {
    return 'baz'
  },
}

const text = JSON.stringify(data, async(key, value) => {
  return value instanceof Promise ? await value : value
})

console.log(text)

So how do I get the value of the promise to be returned by the result of stringify?

>Solution :

You’ll need to deal with the promises first since the JSON.stringify method is synchronous.

async function awaitAllObjectPromises(obj) {
  const newObj = { ...obj
  };
  const proms = [];
  for (const k in newObj) {
    if (newObj[k] instanceof Promise) {
      proms.push(newObj[k].then(v => newObj[k] = v));
    } else if (typeof newObj[k] === 'object' && newObj[k] !== null) {
      proms.push(awaitAllObjectPromises(newObj[k]).then(v => newObj[k] = v));
    }
  }
  await Promise.all(proms);
  return newObj;
}
async function test() {
  const data = {
    foo: "foo",
    get bar() {
      return Promise.resolve('bar')
    },
    get baz() {
      return 'baz'
    },
  }
  console.log(JSON.stringify(await awaitAllObjectPromises(data)));
}
test();

The idea is to go through all the object properties and find promises. Add them to a list of promises to have them resolve in parallel instead of sequentially (small optimization for objects with lots of promises). We do this recursively to make sure we catch all promises.

Using then() we make sure the promises get replaced with their resolved value, and we await them all.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading