Keep object chainable using async methods

前端 未结 3 1289
不思量自难忘°
不思量自难忘° 2021-01-13 06:22

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.

         


        
3条回答
  •  悲&欢浪女
    2021-01-13 07:08

    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

提交回复
热议问题