I have a JSON object I want to stringify. Some of the values in this object are Promises.
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?
You'll need to deal with the promises first since the JSON.stringify method is synchronous.
async function awaitAllObjectPromises(input) {
const output = Array.isArray(input) ? [...input] : {...input}
const promises = []
for (const key in output) {
if (output[key] instanceof Promise) {
promises
.push(
output[key].then(value => output[key] = value)
)
} else if (typeof output[key] === 'object' && output[key] !== null) {
promises
.push(
awaitAllObjectPromises(output[key]).then(value => output[key] = value)
)
}
}
await Promise.all(promises)
return output
}
const data = {
foo: "foo",
blarg: [
Promise.resolve('blarg')
],
get bar() {
return Promise.resolve('bar')
},
get baz() {
return 'baz'
},
}
async function test(subject) {
console.log(JSON.stringify(await awaitAllObjectPromises(subject), null, 4))
}
test(data)
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.