Let\'s say I have a class Test
with around 10-20 methods, all of which are chainable.
In another method, I have some asynchronous work to do.
As discussed in comments to OP, this can be accomplished by using Proxy.
I recognize that t.niese provided a similar answer a few hours ago. My approach differs somewhat, but it's still substantively trapping method calls, returning the receiver and internally stacking up thennables.
class ProxyBase {
constructor () {
// Initialize a base thennable.
this.promiseChain = Promise.resolve();
}
/**
* Creates a new instance and returns an object proxying it.
*
* @return {Proxy}
*/
static create () {
return new Proxy(new this(), {
// Trap all property access.
get: (target, propertyName, receiver) => {
const value = target[propertyName];
// If the requested property is a method and not a reserved method...
if (typeof value === 'function' && !['then'].includes(propertyName)) {
// Return a new function wrapping the method call.
return function (...args) {
target.promiseChain = target.promiseChain.then(() => value.apply(target, args));
// Return the proxy for chaining.
return receiver;
}
} else if (propertyName === 'then') {
return (...args) => target.promiseChain.then(...args);
}
// If the requested property is not a method, simply attempt to return its value.
return value;
}
});
}
}
// Sample implementation class. Nonsense lies ahead.
class Test extends ProxyBase {
constructor () {
super();
this.chainValue = 0;
}
foo () {
return new Promise(resolve => {
setTimeout(() => {
this.chainValue += 3;
resolve();
}, 500);
});
}
bar () {
this.chainValue += 5;
return true;
}
baz () {
return new Promise(resolve => {
setTimeout(() => {
this.chainValue += 7;
resolve();
}, 100);
});
}
}
const test = Test.create();
test.foo().bar().baz().then(() => console.log(test.chainValue)); // 15