refactor(ivy): simplify differentiation of LView, RNode
, LView
, LContainer
, StylingContext
(#28947)
For efficiency reasons we often put several different data types (`RNode`, `LView`, `LContainer`, `StylingContext`) in same location in `LView`. This is because we don't want to pre-allocate space for it because the storage is sparse. This file contains utilities for dealing with such data types. How do we know what is stored at a given location in `LView`. - `Array.isArray(value) === false` => `RNode` (The normal storage value) - `Array.isArray(value) === true` => than the `value[0]` represents the wrapped value. - `typeof value[TYPE] === 'object'` => `LView` - This happens when we have a component at a given location - `typeof value[TYPE] === 'number'` => `StylingContext` - This happens when we have style/class binding at a given location. - `typeof value[TYPE] === true` => `LContainer` - This happens when we have `LContainer` binding at a given location. NOTE: it is assumed that `Array.isArray` and `typeof` operations are very efficient. PR Close #28947
This commit is contained in:

committed by
Miško Hevery

parent
bd65f58784
commit
3cb497c6ac
@ -11,25 +11,22 @@ import {RComment, RElement} from './renderer';
|
||||
import {StylingContext} from './styling';
|
||||
import {HOST, LView, NEXT, PARENT, QUERIES} from './view';
|
||||
|
||||
|
||||
/**
|
||||
* Special location which allows easy identification of type. If we have an array which was
|
||||
* retrieved from the `LView` and that array has `true` at `TYPE` location, we know it is
|
||||
* `LContainer`.
|
||||
*/
|
||||
export const TYPE = 1;
|
||||
/**
|
||||
* Below are constants for LContainer indices to help us look up LContainer members
|
||||
* without having to remember the specific indices.
|
||||
* Uglify will inline these when minifying so there shouldn't be a cost.
|
||||
*/
|
||||
export const ACTIVE_INDEX = 1;
|
||||
export const VIEWS = 2;
|
||||
// PARENT, NEXT, QUERIES, and HOST are indices 2, 3, 4, and 5.
|
||||
export const ACTIVE_INDEX = 2;
|
||||
// PARENT, NEXT, and QUERIES are indices 3, 4, and 5.
|
||||
// As we already have these constants in LView, we don't need to re-create them.
|
||||
export const NATIVE = 6;
|
||||
// Because interfaces in TS/JS cannot be instanceof-checked this means that we
|
||||
// need to rely on predictable characteristics of data-structures to check if they
|
||||
// are what we expect for them to be. The `LContainer` interface code below has a
|
||||
// fixed length and the constant value below references that. Using the length value
|
||||
// below we can predictably gaurantee that we are dealing with an `LContainer` array.
|
||||
// This value MUST be kept up to date with the length of the `LContainer` array
|
||||
// interface below so that runtime type checking can work.
|
||||
export const LCONTAINER_LENGTH = 7;
|
||||
export const VIEWS = 6;
|
||||
export const NATIVE = 7;
|
||||
|
||||
/**
|
||||
* The state associated with a container.
|
||||
@ -51,6 +48,12 @@ export interface LContainer extends Array<any> {
|
||||
*/
|
||||
readonly[HOST]: RElement|RComment|StylingContext|LView;
|
||||
|
||||
/**
|
||||
* This is a type field which allows us to differentiate `LContainer` from `StylingContext` in an
|
||||
* efficient way. The value is always set to `true`
|
||||
*/
|
||||
[TYPE]: true;
|
||||
|
||||
/**
|
||||
* The next active index in the views array to read or write to. This helps us
|
||||
* keep track of where we are in the views array.
|
||||
@ -60,15 +63,6 @@ export interface LContainer extends Array<any> {
|
||||
*/
|
||||
[ACTIVE_INDEX]: number;
|
||||
|
||||
/**
|
||||
* A list of the container's currently active child views. Views will be inserted
|
||||
* here as they are added and spliced from here when they are removed. We need
|
||||
* to keep a record of current views so we know which views are already in the DOM
|
||||
* (and don't need to be re-added) and so we can remove views from the DOM when they
|
||||
* are no longer required.
|
||||
*/
|
||||
[VIEWS]: LView[];
|
||||
|
||||
/**
|
||||
* Access to the parent view is necessary so we can propagate back
|
||||
* up from inside a container to parent[NEXT].
|
||||
@ -85,10 +79,21 @@ export interface LContainer extends Array<any> {
|
||||
* Queries active for this container - all the views inserted to / removed from
|
||||
* this container are reported to queries referenced here.
|
||||
*/
|
||||
[QUERIES]: LQueries|null;
|
||||
[QUERIES]: LQueries|null; // TODO(misko): This is abuse of `LContainer` since we are storing
|
||||
// `[QUERIES]` in it which are not needed for `LContainer` (only needed for Template)
|
||||
|
||||
/**
|
||||
* A list of the container's currently active child views. Views will be inserted
|
||||
* here as they are added and spliced from here when they are removed. We need
|
||||
* to keep a record of current views so we know which views are already in the DOM
|
||||
* (and don't need to be re-added) and so we can remove views from the DOM when they
|
||||
* are no longer required.
|
||||
*/
|
||||
[VIEWS]: LView[];
|
||||
|
||||
/** The comment element that serves as an anchor for this LContainer. */
|
||||
readonly[NATIVE]: RComment;
|
||||
readonly[NATIVE]:
|
||||
RComment; // TODO(misko): remove as this value can be gotten by unwrapping `[HOST]`
|
||||
}
|
||||
|
||||
// Note: This hack is necessary so we don't erroneously get a circular dependency
|
||||
|
@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
|
||||
import {RElement} from './renderer';
|
||||
import {RNode} from './renderer';
|
||||
import {LView} from './view';
|
||||
|
||||
/**
|
||||
@ -39,7 +39,7 @@ export interface LContext {
|
||||
/**
|
||||
* The instance of the DOM node that is attached to the lNode.
|
||||
*/
|
||||
native: RElement;
|
||||
native: RNode;
|
||||
|
||||
/**
|
||||
* The instance of the Component node.
|
||||
|
@ -7,7 +7,10 @@
|
||||
*/
|
||||
import {StyleSanitizeFn} from '../../sanitization/style_sanitizer';
|
||||
import {RElement} from '../interfaces/renderer';
|
||||
import {LContainer} from './container';
|
||||
import {PlayerContext} from './player';
|
||||
import {LView} from './view';
|
||||
|
||||
|
||||
/**
|
||||
* The styling context acts as a styling manifest (shaped as an array) for determining which
|
||||
@ -263,7 +266,7 @@ export interface StylingContext extends
|
||||
/**
|
||||
* Location of element that is used as a target for this context.
|
||||
*/
|
||||
[StylingIndex.ElementPosition]: RElement|null;
|
||||
[StylingIndex.ElementPosition]: LContainer|LView|RElement|null;
|
||||
|
||||
/**
|
||||
* A numeric value representing the configuration status (whether the context is dirty or not)
|
||||
|
@ -72,6 +72,9 @@ export interface LView extends Array<any> {
|
||||
* The host node for this LView instance, if this is a component view.
|
||||
*
|
||||
* If this is an embedded view, HOST will be null.
|
||||
*
|
||||
* If the component uses host bindings for styling that the `RElement` will be wrapped with
|
||||
* `StylingContext`.
|
||||
*/
|
||||
[HOST]: RElement|StylingContext|null;
|
||||
|
||||
|
Reference in New Issue
Block a user