Skip to content
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

refactor(engine): avoiding proxies of proxies in membranes #183

Merged
merged 2 commits into from
Mar 29, 2018

Conversation

caridy
Copy link
Contributor

@caridy caridy commented Mar 28, 2018

Details

This PR prevents:

  • reactive proxies to be rewrapped with a piercing membrane when accessed via public properties of the element.
  • piercing membranes to be rewrapped/accessed via a reactive membrane.

Does this PR introduce a breaking change?

  • No

return unwrapped;
}
// piercing membrane is not that important, it goes second
unwrapped = (value && getKey(value, TargetSlot)) || value;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

simplification of the previous unwrapping method to work faster, no more for-loop, just plain and simple sequencial unwrapping until finding a match.

also I have reordered the sequence to have the most common case first.

@salesforce-best-lwc-internal
Copy link

Benchmark comparison

Base commit: b969b5c | Target commit: b0a5a7c

benchmark base(b969b5c) target(b0a5a7c) trend
table-append-1k.benchmark:benchmark-table/append/1k 255.77 (± 3.80 ms) 246.70 (± 3.39 ms) 👍
table-clear-1k.benchmark:benchmark-table/clear/1k 13.70 (± 0.55 ms) 12.38 (± 0.38 ms) 👍
table-create-10k.benchmark:benchmark-table/create/10k 1447.08 (± 15.90 ms) 1432.34 (± 16.99 ms) 👍
table-create-1k.benchmark:benchmark-table/create/1k 156.89 (± 2.52 ms) 150.83 (± 1.69 ms) 👍
table-update-10th-1k.benchmark:benchmark-table/update-10th/1k 129.43 (± 1.45 ms) 130.62 (± 2.52 ms) 👌
tablecmp-append-1k.benchmark:benchmark-table-component/append/1k 351.09 (± 17.10 ms) 326.91 (± 4.69 ms) 👍
tablecmp-clear-1k.benchmark:benchmark-table/clear/1k 42.46 (± 6.51 ms) 33.05 (± 1.10 ms) 👍
tablecmp-create-10k.benchmark:benchmark-table-component/create/10k 2808.41 (± 258.95 ms) 2473.98 (± 21.52 ms) 👍
tablecmp-create-1k.benchmark:benchmark-table-component/create/1k 273.83 (± 6.03 ms) 268.31 (± 5.15 ms) 👍
tablecmp-update-10th-1k.benchmark:benchmark-table-component/update-10th/1k 121.28 (± 2.12 ms) 115.02 (± 1.98 ms) 👍

import { ReactiveMembrane, unwrap as observableUnwrap } from "observable-membrane";
import { observeMutation, notifyMutation } from "./watcher";

function format(value: any) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

code moved from reactive.ts to avoid circular deps.

if (process.env.NODE_ENV !== 'production') {
// For now, if we determine that value is a piercing membrane
// we want to throw a big error.
if (replicaUnwrap(value) !== value) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is one of the new tricks. This covers the case where:

  • attempting to access a piercing membrane object (we call them replicas) via a reactive membrane.

For now, this only affects dev-mode, and it throws a big error. We can bikeshed on the text of the error!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why throw? Why not just return the unwrapped version and let observable membrane handle it?

return value;
}

export const reactiveMembrane = new ReactiveMembrane(format, {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

code from reactive.ts! intact!

});

// TODO: REMOVE THIS https://github.com/salesforce/lwc/issues/129
export function dangerousObjectMutation(obj: any): any {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

code from reactive.ts! intact!

if (!isReplicable(replicaRawValue)) {
return replicaRawValue;
}
const reactiveRawValue = observableUnwrap(replicaRawValue);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is the second trick! which guarantees that:

  • if you ever access a reactive object via a piercing membrane, what you get is the readonly version of the reactive object.
this.root.querySelector('x-foo').publicPropX; // what you get here is the readOnly version of `publicPropX` from `x-foo` instance.

@@ -1,39 +0,0 @@
import assert from './assert';
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

folding this file into membrane.ts

@@ -58,3 +55,7 @@ export function observeMutation(target: object, key: PropertyKey) {
ArrayPush.call(vm.deps, value);
}
}

import { scheduleRehydration, VM } from "./vm";
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moving these imports down helps with the circular deps problem

@salesforce-best-lwc-internal
Copy link

Benchmark comparison

Base commit: b969b5c | Target commit: b0e5212

benchmark base(b969b5c) target(b0e5212) trend
table-append-1k.benchmark:benchmark-table/append/1k 255.77 (± 3.80 ms) 254.54 (± 8.30 ms) 👌
table-clear-1k.benchmark:benchmark-table/clear/1k 13.70 (± 0.55 ms) 13.69 (± 0.61 ms) 👌
table-create-10k.benchmark:benchmark-table/create/10k 1447.08 (± 15.90 ms) 1444.68 (± 26.34 ms) 👌
table-create-1k.benchmark:benchmark-table/create/1k 156.89 (± 2.52 ms) 152.94 (± 2.52 ms) 👍
table-update-10th-1k.benchmark:benchmark-table/update-10th/1k 129.43 (± 1.45 ms) 130.20 (± 2.48 ms) 👌
tablecmp-append-1k.benchmark:benchmark-table-component/append/1k 351.09 (± 17.10 ms) 327.62 (± 4.11 ms) 👍
tablecmp-clear-1k.benchmark:benchmark-table/clear/1k 42.46 (± 6.51 ms) 34.19 (± 1.98 ms) 👍
tablecmp-create-10k.benchmark:benchmark-table-component/create/10k 2808.41 (± 258.95 ms) 2520.53 (± 40.66 ms) 👍
tablecmp-create-1k.benchmark:benchmark-table-component/create/1k 273.83 (± 6.03 ms) 274.69 (± 6.76 ms) 👌
tablecmp-update-10th-1k.benchmark:benchmark-table-component/update-10th/1k 121.28 (± 2.12 ms) 117.07 (± 2.73 ms) 👍

@@ -10,7 +11,7 @@ describe('unwrap', () => {

it('should unwrap observable membrane object correctly', () => {
const obj = {};
const proxy = membrane.getProxy(obj);
const proxy = reactiveMembrane.getProxy(obj);
expect(unwrap(proxy)).toBe(obj);
Copy link
Contributor

@byao byao Mar 29, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we add test to unwrap and verify not proxy? what check is toBe ?

Copy link
Contributor

@davidturissini davidturissini left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks ok. I would prefer adding a membrane folder, like what we do with decorators, but this'll do for now.

if (process.env.NODE_ENV !== 'production') {
// For now, if we determine that value is a piercing membrane
// we want to throw a big error.
if (replicaUnwrap(value) !== value) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why throw? Why not just return the unwrapped version and let observable membrane handle it?

const getKey = ProxyGetKey ? ProxyGetKey : (o: any, key: PropertyKey): any => o[key];

export function replicaUnwrap(value: any): any {
// observable membrane goes first because it is in the critical path
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this comment makes sense here

Copy link
Contributor

@davidturissini davidturissini left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

change base to 214/patch please We can cherry pick

@davidturissini davidturissini merged commit 7672429 into master Mar 29, 2018
davidturissini pushed a commit that referenced this pull request Mar 29, 2018
* refactor(engine): avoid rewrapping of proxies

* refactor(engine): prevent leaking double proxies via events or querySelector
davidturissini added a commit that referenced this pull request Mar 29, 2018
* refactor(engine): avoid rewrapping of proxies

* refactor(engine): prevent leaking double proxies via events or querySelector
caridy added a commit that referenced this pull request May 2, 2018
* refactor(engine): avoid rewrapping of proxies

* refactor(engine): prevent leaking double proxies via events or querySelector

fix(aom): consolidating the aria dom property names (#192)

wip: Remove slotting

refactor(engine): conditinally  use of native shadowRoot

fix(engine): compat should also work with artificial shadow

refactor(engine): adding slotting

refactor(engine): adding slotting

refactor(engine): conditionally piercing and default behaviors

refactor(engine): minimizing the polyfilling on shadow-root to only AOM

refactor(engine): implementing Pierre's suggestion to avoid patching shadow root prototype
@ekashida ekashida deleted the caridy/214-rewrapping-membranes branch May 2, 2018 18:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants