[Javascript] Covert async code to sync code with throwing Promise
const fetch = () =>
new Promise((res) => {
setTimeout(() => res({ user: 'zhen' }), 1150)
})
globalThis.fetch = fetch
async function getUser() {
return await fetch()
}
async function m1() {
// do something
return await getUser()
}
async function m2() {
// do something
return await m1()
}
async function m3() {
// do something
return await m2()
}
async function main() {
const user = await m3()
console.log('user', user)
}
We want to cover this async code to sync code, which means the following code should work
var fetch = () =>
new Promise((res) => {
setTimeout(() => res({ user: 'zhen' }), 1150)
})
globalThis.fetch = fetch
function getUser() {
return fetch()
}
function m1() {
// do something
return getUser()
}
function m2() {
// do something
return m1()
}
function m3() {
// do something
return m2()
}
function main() {
const user = m3()
console.log('user', user.data)
}
Of course we need to add extra code to make it works.
Idea:
It would be the similar way how React suspend works. When fetching some data using Promise, Suspend check, if you throw a Promise as error, it will wait the promise to be resolved or rejected, it stores all the data into a cache array... then the promise resolved or rejected... then it should rerun the original function again.
var fetch = () =>
new Promise((res) => {
setTimeout(() => res({ user: 'zhen' }), 1150)
})
globalThis.fetch = fetch
function getUser() {
return fetch()
}
function m1() {
// do something
return getUser()
}
function m2() {
// do something
return m1()
}
function m3() {
// do something
return m2()
}
function main() {
const user = m3()
console.log('user', user.data)
}
function run(func) {
const caches = []
let i = 0
const originalFetch = globalThis.fetch
fetch = function (...args) {
if (caches[i]) {
return caches[i]
}
const result = {
status: 'pending',
data: null,
err: null,
}
caches[i++] = result
const promise = originalFetch(...args)
.then((data) => {
result.status = 'fulfilled'
result.data = data
})
.catch((err) => {
result.status = 'rejected'
result.err = err
})
throw promise
}
try {
func()
} catch (err) {
if (err instanceof Promise) {
const rerun = () => {
i = 0
func()
}
err.then(rerun, rerun)
}
}
}
run(main)