5

I have some objects that I am fetching from a web server. Some of the attributes of the objects require additional async parsing, but I want to do that lazily for performance reasons. I am trying to use a proxy to intercept the access and then parse the attribute if accessed. My handler would look something like this

class MyClass {
   type() {
      return "my new class";
   }
}

let myObject = new MyClass();

let proxy = new Proxy(myObject, {
  get: async(target, prop, receiver) => {
    if (prop === "attribute") {
      let newProp = prop + "_parsed";
      if (!(newProp in target)) {
        return await (new Promise((resolve, reject) => { resolve("parsed value") }));
      }
      else {
        return target[newProp];
      }
    }
    else {
      return Reflect.get(target, prop, receiver);
    }
  },
});

console.log(proxy.attribute);  // "parsed value"
console.log(proxy.type()); // "my new class"

If this worked, I would expect to see

parsed value
my new class

but I am getting the following:

{}
{
  "message": "Uncaught TypeError: proxy.type is not a function",
  "filename": "https://stacksnippets.net/js",
  "lineno": 41,
  "colno": 19
}

Is there any way I can return an asynchronous value through a proxy but have the calling code think it is just accessing an attribute? I am even open to forcing the "parse" logic (represented by the promise) to be synchronous, however that has portions that are async so I am not sure how to do that.

1 Answer 1

5

You cannot (should not) use an async method for the get trap. These always return promises, and you want .type to return a function. You'd want to use

async function parseValue() {
  await new Promise(resolve => setImmediate(resolve));
  return "parsed value";
}
let proxy = new Proxy(myObject, {
  get(target, prop, receiver) {
    if (prop === "attribute") {
      let newProp = prop + "_parsed";
      if (!(newProp in target)) {
        target[newProp] = parseValue();
      }
      return target[newProp];
    } else {
      return Reflect.get(target, prop, receiver);
    }
  },
});
…
console.log(await proxy.attribute);
console.log(proxy.type());
Sign up to request clarification or add additional context in comments.

3 Comments

Thank you for the reply, but note the entire reason I am doing this is to avoid the "await" in the "console.log". In my actual application, this value will be used in custom templates, and I want to hide the async behavior from users creating the templates. the Proxy provided a good way to intercept the request to the attribute, but I am having trouble hiding the async nature.
After searching and trying different things (like "deasync"), I basically landed at I will need to accept the fact that "await" will need to be called there. I couldn't find a clean/safe way to force the async commands into a sync-like interface. "require("deasync").sleep(delay);" was the closest I got but it didn't seem safe
You cannot hide async behaviour with a proxy and/or async functions. In javascript, you should embrace asynchrony instead of trying to enforce synchrony. deasync indeed is a horrible hack that leads to unidiomatic and imo errorprone code.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.