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 to minimize the number of redundant iterations #40

Closed
wants to merge 2 commits into from

Conversation

tarabishy2020
Copy link

@tarabishy2020 tarabishy2020 commented Aug 13, 2023

I was going through the code and noticed that SubscribeP function and parseProxyOps are a bit confusing as there are redundant iterations going on there.

parseProxyOps works on the whole set of operations, but those could be related to different paths, yet it's still being called multiple times for each operation.

The refactor makes sure parseProxyOps is called one time. And arrayOps are processed on a per path basis.

@codesandbox-ci
Copy link

codesandbox-ci bot commented Aug 13, 2023

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Latest deployment of this branch, based on commit 3d45aec:

Sandbox Source
React Configuration
React Typescript Configuration

Copy link
Member

@dai-shi dai-shi left a comment

Choose a reason for hiding this comment

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

Thanks for working on it! Started to slowly review the code. Here's the first question.

const index = Number(op[1][op[1].length - 1]);
if (!Number.isFinite(index)) return [];
return [[op[0], index, op[2], op[3]]];
export const parseProxyOps = (ops: Op[]): Record<string, ArrayOp[]> => {
Copy link
Member

Choose a reason for hiding this comment

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

Isn't there a way to do it without changing the signature?

Copy link
Author

Choose a reason for hiding this comment

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

I could maybe call it partitionedProxyOps, call that from subscribeP and leave the original as is, or you were thinking of a different option?

Copy link
Member

Choose a reason for hiding this comment

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

I'm thinking not changing the exported function at all. I might be missing your refactoring point though.

Copy link
Member

Choose a reason for hiding this comment

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

The refactor makes sure parseProxyOps is called one time. And arrayOps are processed on a per path basis.

Maybe my question is whether we can ensure calling the function once, without processing on a per-path basis.

Copy link
Author

@tarabishy2020 tarabishy2020 Aug 15, 2023

Choose a reason for hiding this comment

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

Got you. Yes, we could do that. But then there is no escaping the redundant runs that happen in the aOps forEach.
So below I am just printing the number of iterations for the below example

import * as Y from 'yjs';
import { proxy } from 'valtio/vanilla';
import { bind } from '../src/old/index';
const initData = [...Array(9).keys()];
test.only('dev', async () => {
  const doc = new Y.Doc();
  const a = doc.getMap('arr');

  const p = proxy<any>({
    x: [...initData],
    y: [...initData],
    z: [...initData],
    i: [...initData],
    j: [...initData],
    k: [...initData],
  });
  bind(p, a);
  (() => {
    p.x.reverse();
    p.y.reverse();
    p.z.reverse();
    p.i.reverse();
    p.j.reverse();
    p.k.reverse();
  })();

  expect(true).toBe(true);
});

Before this refactor
image
after
image

Copy link
Member

Choose a reason for hiding this comment

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

I would use a WeakMap for snapshot(proxyObj) to avoid the duplication.

I wonder if we can write a failing test firstly.

Comment on lines +236 to +238
const pathkey = path.join('.');
if (!(pathkey in arrayOpsAll)) return;
const arrayOps = arrayOpsAll[pathkey];
Copy link
Member

Choose a reason for hiding this comment

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

Is the use of pathkey important of the refactoring? Maybe so.
I'm not a big fan of usign . delimiter. What if a path includes the dot?

Copy link
Author

Choose a reason for hiding this comment

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

I don't think it would be of impact here, since we never break on . again, it's merely just a concatenated representation for the parent path, so we can use it as a key to refer to a collection of arrayOps together.

Copy link
Member

Choose a reason for hiding this comment

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

Technically, ["a.b", "c"] and ["a", "b.c"] can conflict.

@dai-shi
Copy link
Member

dai-shi commented Jun 4, 2024

I like the idea to improve the performance, bug #40 (comment) is not acceptable.

@dai-shi dai-shi closed this Jun 4, 2024
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.

2 participants