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

feat(ivy): support object and array literals in render3 #21973

Closed
wants to merge 4 commits into from

Conversation

kara
Copy link
Contributor

@kara kara commented Feb 1, 2018

Currently in render3, if you pass an array literal into a binding, it will be re-created every change detection run and its binding will be re-set every change detection run.

This PR adds a new set of o1()...o8() instructions that ensure the property is only set when one of the bound expressions in the array actually changes.

This template:

<my-comp [names]="['one', myClass, 'two']"></my-comp>

currently generates this instruction:

p(0, 'names', b(['one', ctx.myClass, 'two']));

will generate this instruction:

p(0, 'names', o1(0, e0_literal, 1, ctx.myClass));
...
const e0_literal = ['one', null, 'two'];

@mary-poppins
Copy link

You can preview 02b6bd8 at https://pr21973-02b6bd8.ngbuilds.io/.

@@ -1832,6 +1832,221 @@ export function bind8(
NO_CHANGE;
}

/**
Copy link
Contributor

Choose a reason for hiding this comment

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

instructions.ts is getting large as is. Can we move these into a separate file?

}

/** Updates four expressions in an array literal if they have changed. */
function updateBinding4(
Copy link
Contributor

Choose a reason for hiding this comment

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

Building it up like this is clever. :-)

*/
export function memoize2(arr: any[], index1: number, exp1: any, index2: number, exp2: any): any[]|
NO_CHANGE {
return updateBinding2(arr, index1, exp1, index2, exp2) ? arr.slice() : NO_CHANGE;
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 is right. If I am reading correctly you update the arr and than you make a copy. But arr is the prototype, which means that you are updating it for everyone. I think the correct behavior is to 1) determine if there are changes 2) clone the arr and 3) assign the changes to the array.

Copy link
Contributor Author

@kara kara Feb 1, 2018

Choose a reason for hiding this comment

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

Discussed offline. For anyone curious: the current algorithm works because we are comparing bindings against themselves instead of against the array that is changing. But changing the const array that is generated by the compiler will cause headaches in the compiler code, so instead we will save a copy on TView.

const e0_literal = ['Nancy', null];
// /NORMATIVE

expect(renderComp(MyApp)).toEqual(`<my-comp><p>Nancy</p><p>Bess</p></my-comp>`);
Copy link
Contributor

Choose a reason for hiding this comment

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

assert that e0_literal has not been changed. (I believe that your code changes it which is incorrect.)

@kara kara added action: review The PR is still awaiting reviews from at least one requested reviewer comp: ivy labels Feb 1, 2018
@mary-poppins
Copy link

You can preview b4793f2 at https://pr21973-b4793f2.ngbuilds.io/.

@kara kara added the target: major This PR is targeted for the next major release label Feb 1, 2018
@kara kara changed the title feat(ivy): memoize array literals in render3 feat(ivy): support array literals in render3 Feb 1, 2018
@mary-poppins
Copy link

You can preview a16c5db at https://pr21973-a16c5db.ngbuilds.io/.

Copy link
Contributor

@mhevery mhevery left a comment

Choose a reason for hiding this comment

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

I think the same exact code with few minor changes should work for object literals as well as for arrays.

* @param exp Expression to set at index
* @returns Whether or not there has been a change
*/
function updateArrBinding(arr: any[], index: number, exp: any): boolean {
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this can be updateBinding since Array and Object will have the same exact code.



function getObjectCopy(index: number, arr: any[]): any[] {
const tView = getTView();
Copy link
Contributor

Choose a reason for hiding this comment

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

can you add assert that index comes in the right order? so that we don't create a spares array.

const objectLiterals = tView.objectLiterals;
return objectLiterals && index < objectLiterals.length ?
objectLiterals[index] :
(objectLiterals || (tView.objectLiterals = []))[index] = arr.slice();
Copy link
Contributor

Choose a reason for hiding this comment

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

If you do something like Array.isArray(arr) ? arr.slice() : Object.create(Object, arr). it should work for both array and object. You may want to rename arr => obj

}


function getObjectCopy(index: number, arr: any[]): any[] {
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we call it getMutableBlueprint?

@kara kara changed the title feat(ivy): support array literals in render3 feat(ivy): support object and array literals in render3 Feb 5, 2018
@mary-poppins
Copy link

You can preview b1ce536 at https://pr21973-b1ce536.ngbuilds.io/.

@mhevery mhevery removed the action: review The PR is still awaiting reviews from at least one requested reviewer label Feb 5, 2018
@kara
Copy link
Contributor Author

kara commented Feb 6, 2018

presubmit

@kara kara added the action: merge The PR is ready for merge by the caretaker label Feb 6, 2018
@alxhub alxhub closed this in 4d62be6 Feb 6, 2018
}

/** Updates two expressions in an object literal if they have changed. */
function updateBinding2(obj: any, key1: number, exp1: any, key2: number, exp2: any): boolean {
Copy link
Contributor

@vicb vicb Feb 6, 2018

Choose a reason for hiding this comment

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

string | number (multiples)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good catch. Can include in my follow-up here #22045



/**
* Updates an expression in an object literal if the expression has changed.
Copy link
Contributor

Choose a reason for hiding this comment

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

object literal should be object literal or array

* @param exp Expression to set at key
* @returns A copy of the object or NO_CHANGE
*/
export function objectLiteral1(objIndex: number, obj: any, key: string | number, exp: any): any {
Copy link
Contributor

Choose a reason for hiding this comment

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

objectLiteral is confusing wrt to array ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Since the instruction encompasses both, @mhevery and I discussed using "object" as the more general of the two.

* @param key1
* @param exp1
* @param key2
* @param exp2
Copy link
Contributor

Choose a reason for hiding this comment

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

remove undocumented params ?

jbogarthyde pushed a commit to jbogarthyde/angular that referenced this pull request Feb 23, 2018
leo6104 pushed a commit to leo6104/angular that referenced this pull request Mar 25, 2018
@kara kara deleted the memoize branch October 13, 2018 01:09
@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Sep 14, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
action: merge The PR is ready for merge by the caretaker cla: yes target: major This PR is targeted for the next major release
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants