mr-haili / ng-study Goto Github PK
View Code? Open in Web Editor NEW学习angular实现原理的记录
学习angular实现原理的记录
react的diff
todo
ng2中ngFor的diff, 下面是指令部分的源代码片段:
changes.forEachOperation(
(item: IterableChangeRecord<any>, adjustedPreviousIndex: number, currentIndex: number) => {
if (item.previousIndex == null) {
const view = this._viewContainer.createEmbeddedView(
this._template, new NgForOfContext<T>(null !, this.ngForOf, -1, -1), currentIndex);
const tuple = new RecordViewTuple<T>(item, view);
insertTuples.push(tuple);
} else if (currentIndex == null) {
this._viewContainer.remove(adjustedPreviousIndex);
} else {
const view = this._viewContainer.get(adjustedPreviousIndex) !;
this._viewContainer.move(view, currentIndex);
const tuple = new RecordViewTuple(item, <EmbeddedViewRef<NgForOfContext<T>>>view);
insertTuples.push(tuple);
}
});
在这个变动更新的实现中, 这里执行分成2个部分, diff和patch.
这个方案的好处是实现和理解相对简单, 并且不论数据变动程度如何, 运行速度都相当稳定, 而且diff部分算法复杂度也是非常优秀的O(NlogN).
ps: patch时候有个比较麻烦的地方, adjustedPreviousIndex的求取, 这里需要知道在某一步操作时,
对应的adjustedPreviousIndex和previousIndex之间的偏移, 当操作只有add和remove时恒造成偏移+1, -1,
但是move操作导致的偏移却是动态的.
以下是: angular/packages/core/src/change_detection/differs/default_iterable_differ.ts的部分代码
const adjPreviousIndex = getPreviousIndex(record, addRemoveOffset, moveOffsets);
/* 这里省略了很多代码, 只显示了关键的几行 */
function getPreviousIndex(
item: any, addRemoveOffset: number, moveOffsets: number[] | null): number {
const previousIndex = item.previousIndex;
if (previousIndex === null) return previousIndex;
let moveOffset = 0;
if (moveOffsets && previousIndex < moveOffsets.length) {
moveOffset = moveOffsets[previousIndex];
}
return previousIndex + addRemoveOffset + moveOffset;
}
编辑距离是一种度量两个字符串的不相似度的一种手段。�通过测量最小的编辑操作, 使得源字符串变为目标串。
为了简化问题我们从最简单的情况开始讨论, �对于源字符串s, 定义三种最基本的编辑操作:
TODO 你看见了一个矩阵
�源串: ABCABBA
目标串: CBABAC
对于字符串的编辑与修改可以用一个编辑矩阵来直观的表示, , 而在矩阵上的每一次移动, 对应于一次修改操作, 现在我们看一下每一种移动对应的物理意义, 一个编辑序列可以等价为编辑矩阵上的一条路径:
�在编辑矩阵中的每一步移动, 都可以看做一次不同的编辑操作:
那么我们这个时候考虑一个位置[i, j], �这个位置可能通过3个不同的位置转移过来,
可以表述为,
Levenshtein distance在操作中加入了替换, 当s[i] !=== s[j] 的时候, 我们可以通过一次修改来走斜线。
这次我们换一个思路, 由上文可知,
这一次我们按照拓扑序进行递推,
预处理优化
选择合适算法的策略
post-processing cleanup
export abstract class ViewContainerRef {
abstract get element(): ElementRef;
abstract get injector(): Injector;
abstract get parentInjector(): Injector;
abstract clear(): void;
abstract get(index: number): ViewRef|null;
abstract get length(): number;
abstract createEmbeddedView<C>(templateRef: TemplateRef<C>, context?: C, index?: number):
EmbeddedViewRef<C>;
abstract createComponent<C>(
componentFactory: ComponentFactory<C>, index?: number, injector?: Injector,
projectableNodes?: any[][], ngModule?: NgModuleRef<any>): ComponentRef<C>;
abstract insert(viewRef: ViewRef, index?: number): ViewRef;
abstract move(viewRef: ViewRef, currentIndex: number): ViewRef;
abstract indexOf(viewRef: ViewRef): number;
abstract remove(index?: number): void;
abstract detach(index?: number): ViewRef|null;
}
/* 现在我们以insert接口为例 */
insert(viewRef: ViewRef, index?: number): ViewRef {
if (viewRef.destroyed) {
throw new Error('Cannot insert a destroyed View in a ViewContainer!');
}
const viewRef_ = <ViewRef_>viewRef;
const viewData = viewRef_._view;
attachEmbeddedView(this._view, this._data, index, viewData);
viewRef_.attachToViewContainerRef(this);
return viewRef;
}
export function attachEmbeddedView(
parentView: ViewData, elementData: ElementData, viewIndex: number | undefined | null,
view: ViewData) {
let embeddedViews = elementData.viewContainer !._embeddedViews;
if (viewIndex === null || viewIndex === undefined) {
viewIndex = embeddedViews.length;
}
view.viewContainerParent = parentView;
addToArray(embeddedViews, viewIndex !, view);
attachProjectedView(elementData, view);
Services.dirtyParentQueries(view);
const prevView = viewIndex ! > 0 ? embeddedViews[viewIndex ! - 1] : null;
renderAttachEmbeddedView(elementData, prevView, view);
}
function addToArray(arr: any[], index: number, value: any) {
// perf: array.push is faster than array.splice!
if (index >= arr.length) {
arr.push(value);
} else {
arr.splice(index, 0, value);
}
}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.