skip to Main Content

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:

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?

2

Answers


  1. 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.

    Login or Signup to reply.
  2. This solution makes a recursive resolve of your Promises in object & then u may to stringify it

    async function resolvePromiseJSON(json){
            const copy = Object.assign({}, json)
            for(const key of Object.keys(copy)){
                let value = copy[key]
    
            const isPromise = value instanceof Promise 
            if(isPromise) value = await value
            
            const isArray = value instanceof Array
            if(isArray) value = Object.values(resolvePromiseJSON(value))
    
            const isObject = value instanceof Object
            if(isObject && !isArray) value = resolvePromiseJSON(value)
           
            copy[key] = value
        }
        return copy
    }
    
    resolvePromiseJSON(data).then(JSON.stringify)
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search