Some people are telling you that it can never be done or it's just not going to work. It's not their fault for misunderstanding but you don't need to suffer the same way as them.
Let' say you have an ordinary class, Account
, with a few async
methods -
class Account {
constructor(balance) {
this.balance = balance
}
async withdraw (x) {
await sleep(1000)
this.balance -= x
}
async deposit (x) {
await sleep(1000)
this.balance += x
}
}
sleep
is a simple function which delays the program for ms
milliseconds -
const sleep = ms =>
new Promise(r => setTimeout(r, ms))
Now we can write a chain
function -
const chain = t =>
new Proxy(Promise.resolve(t), { get: get(t) })
const get = t => (target, prop) => (...args) =>
prop === "then"
? target[prop](...args)
: chain(target.then(async v => (await v[prop](...args), v)))
This seemingly allows us to mix synchronous and asynchronous behaviour -
const A = new Account(100)
const B = new Account(200)
chain(A).deposit(5).withdraw(20).then(a => console.log("A", a))
chain(B).withdraw(20).withdraw(30).deposit(10).then(b => console.log("B", b))
Run the snippet below to verify the result in your own browser -
const sleep = ms =>
new Promise(r => setTimeout(r, ms))
const get = t => (target, prop) => (...args) =>
prop === "then"
? target[prop](...args)
: chain(target.then(async v => (await v[prop](...args), v)))
const chain = t =>
new Proxy(Promise.resolve(t), { get: get(t) })
class Account {
constructor(balance) {
this.balance = balance
}
async withdraw (x) {
await sleep(1000)
this.balance -= x
}
async deposit (x) {
await sleep(1000)
this.balance += x
}
}
const A = new Account(100)
const B = new Account(200)
chain(A).deposit(5).withdraw(20).then(a => console.log("A", a))
chain(B).withdraw(20).withdraw(30).deposit(10).then(b => console.log("B", b))
console.log("running...")
A { balance: 85 }
B { balance: 160 }
Invent your own convenience. It's your program to do with as you please.