X Tutup
Skip to content

Commit 7531b48

Browse files
committed
fix(di): instatiate services lazily
1 parent 2bc1217 commit 7531b48

File tree

4 files changed

+207
-76
lines changed

4 files changed

+207
-76
lines changed

modules/angular2/src/core/compiler/element_injector.ts

Lines changed: 113 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -456,7 +456,7 @@ export class ElementInjector extends TreeNode<ElementInjector> implements Depend
456456
this._host = null;
457457
this._preBuiltObjects = null;
458458
this._strategy.callOnDestroy();
459-
this._injector.internalStrategy.dehydrate();
459+
this._strategy.dehydrate();
460460
}
461461

462462
onAllChangesDone(): void {
@@ -476,7 +476,8 @@ export class ElementInjector extends TreeNode<ElementInjector> implements Depend
476476
this._host = host;
477477
this._preBuiltObjects = preBuiltObjects;
478478

479-
this._hydrateInjector(imperativelyCreatedInjector, host);
479+
this._reattachInjectors(imperativelyCreatedInjector, host);
480+
this._strategy.hydrate();
480481

481482
if (isPresent(host)) {
482483
this._addViewQueries(host);
@@ -488,7 +489,7 @@ export class ElementInjector extends TreeNode<ElementInjector> implements Depend
488489
this.hydrated = true;
489490
}
490491

491-
private _hydrateInjector(imperativelyCreatedInjector: Injector, host: ElementInjector): void {
492+
private _reattachInjectors(imperativelyCreatedInjector: Injector, host: ElementInjector): void {
492493
if (isPresent(this._parent)) {
493494
this._reattachInjector(this._injector, this._parent._injector, false);
494495
} else {
@@ -539,7 +540,6 @@ export class ElementInjector extends TreeNode<ElementInjector> implements Depend
539540

540541
private _reattachInjector(injector: Injector, parentInjector: Injector, isBoundary: boolean) {
541542
injector.internalStrategy.attach(parentInjector, isBoundary);
542-
injector.internalStrategy.hydrate();
543543
}
544544

545545
getPipes(): Pipes {
@@ -847,6 +847,8 @@ interface _ElementInjectorStrategy {
847847
buildQueries(): void;
848848
addDirectivesMatchingQuery(q: Query, res: any[]): void;
849849
getComponentBinding(): DirectiveBinding;
850+
hydrate(): void;
851+
dehydrate(): void;
850852
}
851853

852854
/**
@@ -856,6 +858,48 @@ interface _ElementInjectorStrategy {
856858
class ElementInjectorInlineStrategy implements _ElementInjectorStrategy {
857859
constructor(public injectorStrategy: InjectorInlineStrategy, public _ei: ElementInjector) {}
858860

861+
hydrate(): void {
862+
var i = this.injectorStrategy;
863+
var p = i.protoStrategy;
864+
i.resetContructionCounter();
865+
866+
if (p.binding0 instanceof DirectiveBinding && isPresent(p.keyId0) && i.obj0 === undefinedValue)
867+
i.obj0 = i.instantiateBinding(p.binding0, p.visibility0);
868+
if (p.binding1 instanceof DirectiveBinding && isPresent(p.keyId1) && i.obj1 === undefinedValue)
869+
i.obj1 = i.instantiateBinding(p.binding1, p.visibility1);
870+
if (p.binding2 instanceof DirectiveBinding && isPresent(p.keyId2) && i.obj2 === undefinedValue)
871+
i.obj2 = i.instantiateBinding(p.binding2, p.visibility2);
872+
if (p.binding3 instanceof DirectiveBinding && isPresent(p.keyId3) && i.obj3 === undefinedValue)
873+
i.obj3 = i.instantiateBinding(p.binding3, p.visibility3);
874+
if (p.binding4 instanceof DirectiveBinding && isPresent(p.keyId4) && i.obj4 === undefinedValue)
875+
i.obj4 = i.instantiateBinding(p.binding4, p.visibility4);
876+
if (p.binding5 instanceof DirectiveBinding && isPresent(p.keyId5) && i.obj5 === undefinedValue)
877+
i.obj5 = i.instantiateBinding(p.binding5, p.visibility5);
878+
if (p.binding6 instanceof DirectiveBinding && isPresent(p.keyId6) && i.obj6 === undefinedValue)
879+
i.obj6 = i.instantiateBinding(p.binding6, p.visibility6);
880+
if (p.binding7 instanceof DirectiveBinding && isPresent(p.keyId7) && i.obj7 === undefinedValue)
881+
i.obj7 = i.instantiateBinding(p.binding7, p.visibility7);
882+
if (p.binding8 instanceof DirectiveBinding && isPresent(p.keyId8) && i.obj8 === undefinedValue)
883+
i.obj8 = i.instantiateBinding(p.binding8, p.visibility8);
884+
if (p.binding9 instanceof DirectiveBinding && isPresent(p.keyId9) && i.obj9 === undefinedValue)
885+
i.obj9 = i.instantiateBinding(p.binding9, p.visibility9);
886+
}
887+
888+
dehydrate() {
889+
var i = this.injectorStrategy;
890+
891+
i.obj0 = undefinedValue;
892+
i.obj1 = undefinedValue;
893+
i.obj2 = undefinedValue;
894+
i.obj3 = undefinedValue;
895+
i.obj4 = undefinedValue;
896+
i.obj5 = undefinedValue;
897+
i.obj6 = undefinedValue;
898+
i.obj7 = undefinedValue;
899+
i.obj8 = undefinedValue;
900+
i.obj9 = undefinedValue;
901+
}
902+
859903
callOnDestroy(): void {
860904
var i = this.injectorStrategy;
861905
var p = i.protoStrategy;
@@ -938,16 +982,46 @@ class ElementInjectorInlineStrategy implements _ElementInjectorStrategy {
938982
var i = this.injectorStrategy;
939983
var p = i.protoStrategy;
940984

941-
if (isPresent(p.binding0) && p.binding0.key.token === query.selector) list.push(i.obj0);
942-
if (isPresent(p.binding1) && p.binding1.key.token === query.selector) list.push(i.obj1);
943-
if (isPresent(p.binding2) && p.binding2.key.token === query.selector) list.push(i.obj2);
944-
if (isPresent(p.binding3) && p.binding3.key.token === query.selector) list.push(i.obj3);
945-
if (isPresent(p.binding4) && p.binding4.key.token === query.selector) list.push(i.obj4);
946-
if (isPresent(p.binding5) && p.binding5.key.token === query.selector) list.push(i.obj5);
947-
if (isPresent(p.binding6) && p.binding6.key.token === query.selector) list.push(i.obj6);
948-
if (isPresent(p.binding7) && p.binding7.key.token === query.selector) list.push(i.obj7);
949-
if (isPresent(p.binding8) && p.binding8.key.token === query.selector) list.push(i.obj8);
950-
if (isPresent(p.binding9) && p.binding9.key.token === query.selector) list.push(i.obj9);
985+
if (isPresent(p.binding0) && p.binding0.key.token === query.selector) {
986+
if (i.obj0 === undefinedValue) i.obj0 = i.instantiateBinding(p.binding0, p.visibility0);
987+
list.push(i.obj0);
988+
}
989+
if (isPresent(p.binding1) && p.binding1.key.token === query.selector) {
990+
if (i.obj1 === undefinedValue) i.obj1 = i.instantiateBinding(p.binding1, p.visibility1);
991+
list.push(i.obj1);
992+
}
993+
if (isPresent(p.binding2) && p.binding2.key.token === query.selector) {
994+
if (i.obj2 === undefinedValue) i.obj2 = i.instantiateBinding(p.binding2, p.visibility2);
995+
list.push(i.obj2);
996+
}
997+
if (isPresent(p.binding3) && p.binding3.key.token === query.selector) {
998+
if (i.obj3 === undefinedValue) i.obj3 = i.instantiateBinding(p.binding3, p.visibility3);
999+
list.push(i.obj3);
1000+
}
1001+
if (isPresent(p.binding4) && p.binding4.key.token === query.selector) {
1002+
if (i.obj4 === undefinedValue) i.obj4 = i.instantiateBinding(p.binding4, p.visibility4);
1003+
list.push(i.obj4);
1004+
}
1005+
if (isPresent(p.binding5) && p.binding5.key.token === query.selector) {
1006+
if (i.obj5 === undefinedValue) i.obj5 = i.instantiateBinding(p.binding5, p.visibility5);
1007+
list.push(i.obj5);
1008+
}
1009+
if (isPresent(p.binding6) && p.binding6.key.token === query.selector) {
1010+
if (i.obj6 === undefinedValue) i.obj6 = i.instantiateBinding(p.binding6, p.visibility6);
1011+
list.push(i.obj6);
1012+
}
1013+
if (isPresent(p.binding7) && p.binding7.key.token === query.selector) {
1014+
if (i.obj7 === undefinedValue) i.obj7 = i.instantiateBinding(p.binding7, p.visibility7);
1015+
list.push(i.obj7);
1016+
}
1017+
if (isPresent(p.binding8) && p.binding8.key.token === query.selector) {
1018+
if (i.obj8 === undefinedValue) i.obj8 = i.instantiateBinding(p.binding8, p.visibility8);
1019+
list.push(i.obj8);
1020+
}
1021+
if (isPresent(p.binding9) && p.binding9.key.token === query.selector) {
1022+
if (i.obj9 === undefinedValue) i.obj9 = i.instantiateBinding(p.binding9, p.visibility9);
1023+
list.push(i.obj9);
1024+
}
9511025
}
9521026

9531027
getComponentBinding(): DirectiveBinding {
@@ -963,6 +1037,23 @@ class ElementInjectorInlineStrategy implements _ElementInjectorStrategy {
9631037
class ElementInjectorDynamicStrategy implements _ElementInjectorStrategy {
9641038
constructor(public injectorStrategy: InjectorDynamicStrategy, public _ei: ElementInjector) {}
9651039

1040+
hydrate(): void {
1041+
var inj = this.injectorStrategy;
1042+
var p = inj.protoStrategy;
1043+
1044+
for (var i = 0; i < p.keyIds.length; i++) {
1045+
if (p.bindings[i] instanceof DirectiveBinding && isPresent(p.keyIds[i]) &&
1046+
inj.objs[i] === undefinedValue) {
1047+
inj.objs[i] = inj.instantiateBinding(p.bindings[i], p.visibilities[i]);
1048+
}
1049+
}
1050+
}
1051+
1052+
dehydrate(): void {
1053+
var inj = this.injectorStrategy;
1054+
ListWrapper.fill(inj.objs, undefinedValue);
1055+
}
1056+
9661057
callOnDestroy(): void {
9671058
var ist = this.injectorStrategy;
9681059
var p = ist.protoStrategy;
@@ -983,7 +1074,8 @@ class ElementInjectorDynamicStrategy implements _ElementInjectorStrategy {
9831074
}
9841075

9851076
buildQueries(): void {
986-
var p = this.injectorStrategy.protoStrategy;
1077+
var inj = this.injectorStrategy;
1078+
var p = inj.protoStrategy;
9871079

9881080
for (var i = 0; i < p.bindings.length; i++) {
9891081
if (p.bindings[i] instanceof DirectiveBinding) {
@@ -997,7 +1089,12 @@ class ElementInjectorDynamicStrategy implements _ElementInjectorStrategy {
9971089
var p = ist.protoStrategy;
9981090

9991091
for (var i = 0; i < p.bindings.length; i++) {
1000-
if (p.bindings[i].key.token === query.selector) list.push(ist.objs[i]);
1092+
if (p.bindings[i].key.token === query.selector) {
1093+
if (ist.objs[i] === undefinedValue) {
1094+
ist.objs[i] = ist.instantiateBinding(p.bindings[i], p.visibilities[i]);
1095+
}
1096+
list.push(ist.objs[i]);
1097+
}
10011098
}
10021099
}
10031100

modules/angular2/src/di/injector.ts

Lines changed: 9 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -192,8 +192,8 @@ export interface InjectorStrategy {
192192
getMaxNumberOfObjects(): number;
193193

194194
attach(parent: Injector, isBoundary: boolean): void;
195-
hydrate(): void;
196-
dehydrate(): void;
195+
resetContructionCounter(): void;
196+
instantiateBinding(binding: ResolvedBinding, visibility: number): any;
197197
}
198198

199199
export class InjectorInlineStrategy implements InjectorStrategy {
@@ -210,33 +210,10 @@ export class InjectorInlineStrategy implements InjectorStrategy {
210210

211211
constructor(public injector: Injector, public protoStrategy: ProtoInjectorInlineStrategy) {}
212212

213-
hydrate(): void {
214-
var p = this.protoStrategy;
215-
var inj = this.injector;
213+
resetContructionCounter(): void { this.injector._constructionCounter = 0; }
216214

217-
inj._constructionCounter = 0;
218-
219-
220-
if (isPresent(p.keyId0) && this.obj0 === undefinedValue)
221-
this.obj0 = inj._new(p.binding0, p.visibility0);
222-
if (isPresent(p.keyId1) && this.obj1 === undefinedValue)
223-
this.obj1 = inj._new(p.binding1, p.visibility1);
224-
if (isPresent(p.keyId2) && this.obj2 === undefinedValue)
225-
this.obj2 = inj._new(p.binding2, p.visibility2);
226-
if (isPresent(p.keyId3) && this.obj3 === undefinedValue)
227-
this.obj3 = inj._new(p.binding3, p.visibility3);
228-
if (isPresent(p.keyId4) && this.obj4 === undefinedValue)
229-
this.obj4 = inj._new(p.binding4, p.visibility4);
230-
if (isPresent(p.keyId5) && this.obj5 === undefinedValue)
231-
this.obj5 = inj._new(p.binding5, p.visibility5);
232-
if (isPresent(p.keyId6) && this.obj6 === undefinedValue)
233-
this.obj6 = inj._new(p.binding6, p.visibility6);
234-
if (isPresent(p.keyId7) && this.obj7 === undefinedValue)
235-
this.obj7 = inj._new(p.binding7, p.visibility7);
236-
if (isPresent(p.keyId8) && this.obj8 === undefinedValue)
237-
this.obj8 = inj._new(p.binding8, p.visibility8);
238-
if (isPresent(p.keyId9) && this.obj9 === undefinedValue)
239-
this.obj9 = inj._new(p.binding9, p.visibility9);
215+
instantiateBinding(binding: ResolvedBinding, visibility: number): any {
216+
return this.injector._new(binding, visibility);
240217
}
241218

242219
attach(parent: Injector, isBoundary: boolean): void {
@@ -245,19 +222,6 @@ export class InjectorInlineStrategy implements InjectorStrategy {
245222
inj._isBoundary = isBoundary;
246223
}
247224

248-
dehydrate() {
249-
this.obj0 = undefinedValue;
250-
this.obj1 = undefinedValue;
251-
this.obj2 = undefinedValue;
252-
this.obj3 = undefinedValue;
253-
this.obj4 = undefinedValue;
254-
this.obj5 = undefinedValue;
255-
this.obj6 = undefinedValue;
256-
this.obj7 = undefinedValue;
257-
this.obj8 = undefinedValue;
258-
this.obj9 = undefinedValue;
259-
}
260-
261225
getObjByKeyId(keyId: number, visibility: number): any {
262226
var p = this.protoStrategy;
263227
var inj = this.injector;
@@ -352,13 +316,10 @@ export class InjectorDynamicStrategy implements InjectorStrategy {
352316
ListWrapper.fill(this.objs, undefinedValue);
353317
}
354318

355-
hydrate(): void {
356-
var p = this.protoStrategy;
357-
for (var i = 0; i < p.keyIds.length; i++) {
358-
if (isPresent(p.keyIds[i]) && this.objs[i] === undefinedValue) {
359-
this.objs[i] = this.injector._new(p.bindings[i], p.visibilities[i]);
360-
}
361-
}
319+
resetContructionCounter(): void { this.injector._constructionCounter = 0; }
320+
321+
instantiateBinding(binding: ResolvedBinding, visibility: number): any {
322+
return this.injector._new(binding, visibility);
362323
}
363324

364325
attach(parent: Injector, isBoundary: boolean): void {
@@ -367,8 +328,6 @@ export class InjectorDynamicStrategy implements InjectorStrategy {
367328
inj._isBoundary = isBoundary;
368329
}
369330

370-
dehydrate(): void { ListWrapper.fill(this.objs, undefinedValue); }
371-
372331
getObjByKeyId(keyId: number, visibility: number): any {
373332
var p = this.protoStrategy;
374333

modules/angular2/test/core/compiler/element_injector_spec.ts

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -661,17 +661,49 @@ export function main() {
661661
expect(inj.get(NeedsService).service).toEqual('service');
662662
});
663663

664-
it("should not instantiate other directives that depend on viewInjector bindings",
665-
() => {
666-
var directiveAnnotation = new dirAnn.Component({
667-
viewInjector: ListWrapper.concat([bind("service").toValue("service")], extraBindings)
668-
});
669-
var componentDirective =
670-
DirectiveBinding.createFromType(SimpleDirective, directiveAnnotation);
671-
expect(() => { injector([componentDirective, NeedsService], null); })
672-
.toThrowError(containsRegexp(
673-
`No provider for service! (${stringify(NeedsService) } -> service)`));
664+
it("should instantiate hostInjector injectables lazily", () => {
665+
var created = false;
666+
var inj = injector(
667+
ListWrapper.concat([DirectiveBinding.createFromType(SimpleDirective, new dirAnn.Component({
668+
hostInjector: [bind('service').toFactory(() => created = true)]
669+
}))],
670+
extraBindings),
671+
null, true);
672+
673+
expect(created).toBe(false);
674+
675+
inj.get('service');
676+
677+
expect(created).toBe(true);
678+
});
679+
680+
it("should instantiate viewInjector injectables lazily", () => {
681+
var created = false;
682+
var inj = injector(
683+
ListWrapper.concat([DirectiveBinding.createFromType(SimpleDirective, new dirAnn.Component({
684+
viewInjector: [bind('service').toFactory(() => created = true)]
685+
}))],
686+
extraBindings),
687+
null, true);
688+
689+
expect(created).toBe(false);
690+
691+
inj.get('service');
692+
693+
expect(created).toBe(true);
694+
});
695+
696+
it("should not instantiate other directives that depend on viewInjector bindings",
697+
() => {
698+
var directiveAnnotation = new dirAnn.Component({
699+
viewInjector: ListWrapper.concat([bind("service").toValue("service")], extraBindings)
674700
});
701+
var componentDirective =
702+
DirectiveBinding.createFromType(SimpleDirective, directiveAnnotation);
703+
expect(() => { injector([componentDirective, NeedsService], null); })
704+
.toThrowError(containsRegexp(
705+
`No provider for service! (${stringify(NeedsService) } -> service)`));
706+
});
675707

676708
it("should instantiate directives that depend on hostInjector bindings of other directives", () => {
677709
var shadowInj = hostShadowInjectors(

0 commit comments

Comments
 (0)
X Tutup