stack overflow when returning an ES6 proxy through

2019-05-31 16:19发布

问题:

I'm trying to intercept a method call on a ES6 proxy to be able to do stuff in between with the information I get from the proxy. Now in my case there is quite some stuff going on before creating and returning the proxy from some kind of factory. Because of all this stuff I decided to wrap the prerequisites into a promise-function so that I can chain the proxy creation right onto it and return the resulting proxy through the promise chain. Here's the code to reproduce the problem:

proxy_factory.min.js

'use strict';

// require('harmony-reflect');

class ProxyFactory {

  create(options) {

    const self = this;

    const handler = {

      get(target, propertyKey, receiver) {

        if (propertyKey === 'then') {

          return function proxyPromiseWrapper(thenCallback) {
            const innerProxy = self.create(options);
            return thenCallback(innerProxy);
          };
        }

        return function resourceFunctionProxy() {

          const callContext = {
            target: target,
            method: propertyKey,
            args: arguments,
            thisContext: this
          };

          const resourceInstanceMethod = Reflect.get(options.originalObject, callContext.method);
          return resourceInstanceMethod.apply(callContext.thisContext, callContext.arguments);

        };
      }
    };

    return new Proxy(options.originalObject, handler);
  }

}

module.exports = ProxyFactory;

test.js

'use strict';

const Promise = require('bluebird');
const ProxyFactory = require('./proxy_factory.min.js');

const proxyFactory = new ProxyFactory();

function createProxyWithPromise() {

  const TestClass = class {
    doSomething() {
      return Promise.resolve('promise return value');
    }
  };

  const options = {
    originalObject: new TestClass()
  };

  return Promise.resolve()
    .then(() => {
      return proxyFactory.create(options);
    });
}

function test() {

  createProxyWithPromise()
    .then((proxy) => {

      const result = proxy.doSomething();

      console.log(result); // should output 'promisereturnvalue'
    });
}

test();

Before doSomething() is called on the proxy the then()-function is called over and over again, resulting in a stack overflow. I already asked this question in the node.js github issues and you can find the previous conversation here: https://github.com/nodejs/node/issues/8082 Maybe it helps someone helping me ;)

回答1:

Your problem is that your proxy always returns a function for accesses on any property, including then. That will make promises implementations treat it as a thenable, trying to to resolve it - where your code went horribly wrong. But you should fix the root of the issue:

get (target, propertyKey, receiver) {
    if (!(propertyKey in target))
        return undefined;
    else if (typeof target[propertyKey] != "function")
        return …;
    else
        return function resourceFunctionProxy() {
            …


回答2:

It's a shot in the blue, but you might be looking for

return function proxyPromiseWrapper(thenCallback) {
    return options.originalObject.then(function(result) {
        const resultOptions = Object.assign({}, options, {target: result});
        const innerProxy = self.create(resultOptions);
        return thenCallback(innerProxy);
    });
};