-
Notifications
You must be signed in to change notification settings - Fork 14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use Proxy.revokable and add revokeProxy to API #4
Conversation
src/jsonpatcherproxy.js
Outdated
@@ -8,6 +8,7 @@ | |||
/** Class representing a JS Object observer */ | |||
var JSONPatcherProxy = (function() { | |||
function JSONPatcherProxy(root) { | |||
this.proxifiedObjectsMap = []; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A WeakMap here would be more memory-friendly.
src/jsonpatcherproxy.js
Outdated
return proxy; | ||
/* keeping track of all the proxies to be able to revoke them later */ | ||
this.proxifiedObjectsMap.push(proxy); | ||
return proxy.proxy; | ||
}; | ||
//grab tree's leaves one by one, encapsulate them into a proxy and return | ||
JSONPatcherProxy.prototype._proxifyObjectTreeRecursively = function( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could _proxifyObjectTreeRecursively
automatically revoke proxy of when a child object is removed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@warpech I started with this yesterday but figured that would render the child object useless even if it was cached earlier on purpose for later usages, like in this demo. Doing it in Palindrom made more sense since Palindrom.obj
is ours and we give it to the user for use, so we have the right to destroy parts of it.
But the observed object in JSONPatcherProxies is not ours and I guess we should leave it, and its children, usable.
What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see my mistake here. Children will emit patches to the same callback of the parent object even after they are deleted, which is problematic. I think disabling the traps inside _proxifyObjectTreeRecursively
would be the safest option.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great, then let's do it like you say.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@alshakero The jsbin throws 504 to me :| could you send it once again?
Forgive me if I get something wrong. I still don't get why can we revoke
on deleteProperty
by default.
But the observed object in JSONPatcherProxies is not ours and I guess we should leave it, and its children, usable.
If child proxy object "was cached earlier on purpose for later usages". It's a proxy object, so it's ours and we can destroy it. If user wants to cache his/hers object for later usages after it's unobserved by us, he/she can use originalObject
or the object returned by delete/splice - I believe it's the original one https://github.com/Palindrom/JSONPatcherProxy/pull/4/files?w=1#diff-3bfa726203c6cb018f2321c18ca9298eR94 . I'm not sure, @alshakero is it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@tomalec now I implemented the ability to disable traps for a given proxy, and this happens automatically in deleteProperty
trap. It's more fail-proof. And I regret the revoking proposal, it's redundant now. I'll explain:
If an element (say an HTML input
field) is bound to a sub-object of the state tree using Polymer binding. And a patch comes to delete that sub-object from the server, editing the field will throw a TypeError (in the time window of Polymer binding async update), and this error will be to the user in production, not to the developer. Any race condition will cause this issue and it will be very hard to reproduce.
WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@tomalec the whole JSBin is down 🤒
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you use jsfiddle.net?
Once delete patch is applied binding should be removed as well.
If you are talking about race conditions between browser-to-server and server-to-browser messages, OT should solve it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@tomalec I don't see any objective argument for revoking against disabling traps. And since I implemented disabling traps, I naturally lean to less redundant work. Do you have any reason to prefer throwing an error rather than covering the edge-case by simply disabling the proxy?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we setup a HO call, I feel I miss something in here.
src/jsonpatcherproxy.js
Outdated
*/ | ||
JSONPatcherProxy.prototype.revokeProxy = function(proxy) { | ||
let deletedIndex; | ||
this.proxifiedObjectsMap.forEach(function(el, index) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With WeakMap this becomes simpler: this.proxifiedObjectsMap.get(proxy)
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Totally forgot about its whole existence! Great idea.
And add specs for either case
Just added a comment at https://github.com/Palindrom/JSONPatcherProxy/pull/4/files/a50598b02b1a7c4f34e89afcf5e902defeb83d52#r115702691 but GH hides it. |
@tomalec here is my response in case it was hidden: #4 (comment) |
- Modify TS typings accordingly - Use `Map` instead of `WeakMap` (Itertable) - Add specs for all new functions and checking for detached warnings - Disable UglifyJS for now (No ES6 Support)
@tomalec I think this is ready for review. |
README.md
Outdated
|
||
#### JSONPatcherProxy#switchCallbackOff () : void | ||
Enables patches omitting (to both callback and patches array). Starting from the moment you call it. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would think resume
would resume observing/notifying changes, so it would "Disable patches omitting".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What an unlucky typo. I mean emitting.
src/jsonpatcherproxy.js
Outdated
return obj; | ||
} | ||
var instance = this; | ||
var trapsInstance = Object.assign({}, traps, {path: path, instance: instance}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isn't
trapsInstance.path = path;
trapsInstance.instance = instance;
cheaper?
Or even just define traps in here, without a need to create 3 new objects?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's right. I thought not defining the functions (set
, get
etc..) again and just referencing them would be better. But this would be slower with every issued patch (this.instance.defaultCallback
is slow).
Moving them inside could be a little slower but for one time only. Faster with every patch.
I moved it inside.
@tomalec is this good to merge? |
README.md
Outdated
|
||
Turns the proxified object into a forward-proxy object; doesn't emit any patches anymore, like a normal object.. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does ..
stands for ellipsis, or it's just one dot too much?
src/jsonpatcherproxy.js
Outdated
/** | ||
* Creates an instance of JSONPatcherProxy around your object of interest `root`. | ||
* @param {Object|Array} root - the object you want to wrap | ||
* @param {Boolean} showDetachedWarning - whether to log a warning when a detached sub-object is modified @see {@link https://github.com/Palindrom/JSONPatcherProxy#detached-objects} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
WDYT about adding optional parameter info and default values in jsdoc? http://usejsdoc.org/tags-param.html#optional-parameters-and-default-values
src/jsonpatcherproxy.js
Outdated
* Disables all proxies' traps, turning the observed object into a forward-proxy object, like a normal object that you can modify silently. | ||
*/ | ||
JSONPatcherProxy.prototype.disableTraps = function() { | ||
proxifiedObjectsMap.forEach(disableTrapsForProxy.bind(this)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why don't we make disableTrapsForProxy
instance method as we are always calling it on instance - it results in creating new function of every call, here and on delete? Do you want to keep it private?
test/spec/proxySpec.js
Outdated
}); | ||
|
||
observedObj.firstName = 'Malvin'; | ||
expect(called).toReallyEqual(1); | ||
it('should omit patches when unobserved then observed', function () { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We are testing pause
and resume
not "unobservered" then "observed"
test/spec/proxySpec.js
Outdated
}); | ||
it('should unobserve then observe again (deep value)', function () { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and we have unobserve
again, It's quite confusing to me to mix pause
and unobserve
test together, under describe('unobserving', function(){
Overall I think it's just cosmetics, but |
@tomalec we have done all kinds of breaking changes, why should we keep |
test/spec/proxySpec.js
Outdated
}); | ||
|
||
describe('pausing and resuming', function() { | ||
it("shouldn't omit patches when paused", function() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it should be: "Should omit patches when paused"
test/spec/proxySpec.js
Outdated
expect(called).toReallyEqual(2); | ||
}); | ||
|
||
it('should omit patches when paused then resumed', function() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd say: "Should re-start emitting patches when paused then resumed"
Is this good to go? |
I'm implementing the needed specs right now.
Implements: Palindrom/Palindrom#134