Proxy get handler called on evaluation of proxy - javascript

I defined a proxy as follows:
const o1 = {
ready: false
};
setTimeout(() => {
o1.ready = true;
}, 1000000000);
const handler = {
get(target, propKey, receiver) {
if (target.ready == false) {
throw new Error('not ready');
} else {
return 'ready'
}
}
};
const proxy = new Proxy(o1, handler);
proxy; // raises 'not ready'
Evaluating proxy raises the error 'not ready', even though it isnt a property access. How do I prevent the error from being raised when the reference to the proxy is evaluated? This causes bugs when requiring without assignment.

It seems to be related to this bug: https://github.com/nodejs/node/issues/10731
The best work around I've found is to specifically ignore the node inspection:
const handler = {
get(target, propKey, receiver) {
if (propKey != util.inspect.custom &&
propKey != 'inspect' &&
propKey != Symbol.toStringTag){
if (target.ready == false) {
throw new Error('not ready');
} else {
return 'ready'
}
}
}
};
Or alternatively if you knew the list of keys you cared about then just check those instead of excluding.

Apparently you're evaluating this in the REPL, where the final proxy; statement makes for the result value of the code and which is logged to the console. Logging it will access the properties, that's expected.
However, you really should not be using a proxy here. A proxy should handle different properties individually, but yours appears to only care about the ready property. A simpler getter would be more appropriate:
const o1 = {
ready: false
};
setTimeout(() => {
o1.ready = true;
}, 1000000000);
const res = { // instead of the `proxy` object
get ready() {
if (o1.ready == false) {
throw new Error('not ready');
} else {
return 'ready'
}
}
};
res.ready // either throws or yields the string "ready"

Related

Javascript Class - Chaining async methods and returning "this"

I'm attempting to introduce a queue-type system to a JS class to allow for Async method chaining, ideally, I'd like to perform operations on the class instance using these async methods and return "this" instance.
export class Queue {
constructor() {
this.queue = Promise.resolve()
this.firstRequestStarted = false
this.firstRequestStatusCode = 0
this.secondRequestStarted = false
this.secondRequestStatusCode = 0
}
then(callback) {
callback(this.queue)
}
chain(callback) {
return this.queue = this.queue.then(callback)
}
first() {
this.chain(async () => {
try {
this.firstRequestStarted = true
const response = await axios.get("https://stackoverflow.com/questions")
this.firstRequestStatusCode = response.status
return this
}
catch (e) {
const { message = "" } = e || {}
return Promise.reject({ message })
}
})
return this
}
second() {
this.chain(async () => {
try {
this.secondRequestStarted = true
const response = await axios.get("https://stackoverflow.com/")
this.secondRequestStatusCode = response.status
return this
}
catch (e) {
const { message = "" } = e || {}
return Promise.reject({ message })
}
})
return this
}
}
Functions are added to the queue, and as we await them, the "then" method will handle their execution.
const x = await new Queue()
.first()
.second()
console.log(x)
The challenge I'm facing is that I can never actually get "this" (instance of Queue) back to x.
1) x === undefined
2) "Chaining cycle detected for promise #<Promise>"
or ( I haven't been able to track down where this one is coming from, node error)
3) finished with exit code 130 (interrupted by signal 2: SIGINT)
I have tried adding a "consume" method, which simply returns "this", this leads to error #2 above
me() {
this.chain( () => {
try {
return this
}
catch (e) {
const { message = "" } = e || {}
return Promise.reject({ message })
}
})
return this
}
The confusion on my part, is that if I use any value other than "this", it works as expected
me() {
this.chain( () => {
try {
return "test"
}
catch (e) {
const { message = "" } = e || {}
return Promise.reject({ message })
}
})
return this
}
x === "test"
I'm also able to return the values associated to this with something like the following
return {...this}
Ideally, I'd like to return the instance of Queue to X, as I plan on modifying the properties of the Queue instance through my async methods, await them, and be returned with an "initialized" instance of Queue.
Any input would be greatly appreciated - thank you!
The problem is that your Queue instances are thenable (have a .then() method), and the promise is tried to be resolved with itself (this.queue). See also here or there.
You have two options:
Do not resolve your promise with the instance, but write
const x = new Queue().first().second();
await x;
console.log(x);
remove the then method from your class, then call
const x = new Queue().first().second().queue;
console.log(x);
(or possibly introduce a getter method - .get(), .toPromise() - instead of directly accessing .queue)

How to update state with an error message in React?

Hi I was trying to update state depending on the error message caught. My code is:
const [errors,setErrors] = useState("Blah blah");
const verifyIfObject = (object) => {
try {
if (object === "object") {
return true;
} else {
const errMsg = `Error: ${object} is not a js object...`;
throw errMsg;
}
}
catch (e) {
console.log(e);
setErrors(e);
}
};
When executing the code with error I get the error message in console:
"Uncaught Error: Too many re-renders. React limits the number of renders to prevent an infinite loop."
Please advise how to change the code so that error messages can be stored in state
a try/catch block needs to be used in an async function. You may simplify your function like this:
const [errors,setErrors] = useState("Blah blah");
const verifyIfObject = (object) => {
if (object !== "object") {
setErrors(`Error: ${object} is not a js object...`);
return false
}
return true
};

How can I return an error from a function?

Let's say I have a function like this:
const getPlayer = (id) => {
return players[id;]
}
//--------------------------
const client = getPlayer(9);
How can I return the err parameter to the client variable if no player is found? For example:
if (client.err) {
//do something
}
I tried passing the error via throw new Error('my error') , but the function still doesn't get it, what am I doing wrong?:(
So your first instinct was correct, you should use the 'throw' keyword to raise an error. To act on the error you need to use try/catch like I've done below.
const getPlayer = (id) => {
if(id in players) {
return players[id];
}
throw new Error("Oh noes...!");
}
try {
const client = getPlayer(9);
} catch(error) {
console.log(error.message);
}
When an error is thrown inside a function being executed in a try block, execution immediately jumps to the catch block, allowing you to respond to the error appropriately.
Checkout try/catch syntax for that.
For example:
const getPlayer = (id) => {
if (!id) {
throw new Error('no id provided');
}
return players[id]
}
To get this "error" state, when it triggers you can do following:
try {
const client = getPlayer(null);
} catch(error) {
console.log(error.message);
}
I have tried something but not sure if this is what you are after:
let a = (x) => {
if (x == 0) {
throw new Error("Votes are zero");
} else {
return x;
}
};
Run it in the console with the values as a(0) --> will throw you a new error and a(5)

JavaScript proxy return async value on "get"

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.
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());

test works with jasmine-node, but not and with jasmine

I have a object that is subscribed to the uncaught error event and I am trying to test its behaviour. First I tried with jasmine-node, but now when I am trying to go with jasmine I found trouble. Could anyone help me.
describe('Constructor tests', function () {
it('error is passed to the callback', function (done) {
const error = new Error("testError-0");
let errorHandler = new AllErrorHandler((arg1) => {
expect(arg1).toBe(error);
errorHandler.dispose();
done();
});
setTimeout(() => {
throw error;
}, 0)
});
Thanks in advance.
I got this working when executed directly via jasmine when the jasmine ./tests/alLErrorException.spec.js command is run. The following changes were required:
Always setup the listeners, even when the _callback should not be executed.
constructor(callback, startListening = true) {
if (!callback) {
throw new Error("Missing callback function");
}
this._callback = callback;
this._listening = startListening;
this._setupEvents();
}
Add a function to intercept uncaughtException events and to call the _callback if we are _listening:
_handler() {
if(this._listening) {
this._callback.apply(null, arguments);
}
}
Remove all other uncaughtException event handlers in _setupEvents:
_setupEvents(attatch = true) {
this._listening = attatch ? true : false;
if (attatch) {
if (typeof window !== "undefined") {
window.addEventListener("error", this._callback);
} else {
// Added this line
process.removeAllListeners('uncaughtException');
process.addListener('uncaughtException', this._handler.bind(this));
}
} else {
if (typeof window !== "undefined") {
window.removeEventListener("error", this._callback);
} else {
process.removeListener('uncaughtException', this._callback);
}
}
}
This is required because jasmine sets up it's own uncaughtException handler and reports an error even though the error was caught by the AllErrorHandler class.
Here is a paste of the full source for the AllErrorHandler class with the required changes.

Categories

Resources