注入Provider(异步工厂)
将抽象类绑定到Provider。Provider是一个异步工厂,这在处理异步I/O操作时非常有用。
type KatanaProvider = () => Promise<Katana>;
@injectable()
class Ninja implements Ninja {
public katana: Katana;
public shuriken: Shuriken;
public katanaProvider: KatanaProvider;
public constructor(
@inject("KatanaProvider") katanaProvider: KatanaProvider,
@inject("Shuriken") shuriken: Shuriken
) {
this.katanaProvider = katanaProvider;
this.katana= null;
this.shuriken = shuriken;
}
public fight() { return this.katana.hit(); };
public sneak() { return this.shuriken.throw(); };
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
container.bind<KatanaProvider>("KatanaProvider").toProvider<Katana>((context) => {
return () => {
return new Promise<Katana>((resolve) => {
let katana = context.container.get<Katana>("Katana");
resolve(katana);
});
};
});
var ninja = container.get<Ninja>("Ninja");
ninja.katanaProvider()
.then((katana) => { ninja.katana = katana; })
.catch((e) => { console.log(e); });
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
提供自定义参数
绑定toProvider
需要ProviderCreator
作为其唯一参数:
interface ProviderCreator<T> extends Function {
(context: Context): Provider<T>;
}
1
2
3
2
3
provider
的格式如下:
interface Provider<T> extends Function {
(...args: any[]): (((...args: any[]) => Promise<T>) | Promise<T>);
}
1
2
3
2
3
遵循上面的格式,我们就能够向provider
传递自定义参数了:
let container = new Container();
interface Sword {
material: string;
damage: number;
}
@injectable()
class Katana implements Sword {
public material: string;
public damage: number;
}
type SwordProvider = (material: string, damage: number) => Promise<Sword>;
container.bind<Sword>("Sword").to(Katana);
container.bind<SwordProvider>("SwordProvider").toProvider<Sword>((context) => {
return (material: string, damage: number) => { // 自定义参数
return new Promise<Sword>((resolve) => {
setTimeout(() => {
let katana = context.container.get<Sword>("Sword");
katana.material = material;
katana.damage = damage;
resolve(katana);
}, 10);
});
};
});
let katanaProvider = container.get<SwordProvider>("SwordProvider");
katanaProvider("gold", 100).then((powerfulGoldKatana) => { // 使用所有自定义参数
expect(powerfulGoldKatana.material).to.eql("gold");
expect(powerfulGoldKatana.damage).to.eql(100);
});
katanaProvider("gold", 10).then((notSoPowerfulGoldKatana) => {
expect(notSoPowerfulGoldKatana.material).to.eql("gold");
expect(notSoPowerfulGoldKatana.damage).to.eql(10);
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
Provider 部分应用
我们还可以使用部分应用来传递参数
let container = new Container();
interface Sword {
material: string;
damage: number;
}
@injectable()
class Katana implements Sword {
public material: string;
public damage: number;
}
type SwordProvider = (material: string) => (damage: number) => Promise<Sword>;
container.bind<Sword>("Sword").to(Katana);
container.bind<SwordProvider>("SwordProvider").toProvider<Sword>((context) => {
return (material: string) => { // 自定义参数 1!
return (damage: number) => { // 自定义参数 2!
return new Promise<Sword>((resolve) => {
setTimeout(() => {
let katana = context.container.get<Sword>("Sword");
katana.material = material;
katana.damage = damage;
resolve(katana);
}, 10);
});
};
};
});
let katanaProvider = container.get<SwordProvider>("SwordProvider");
let goldKatanaProvider = katanaProvider("gold"); // 应用第一个自定义参数!
goldKatanaProvider(100).then((powerfulGoldKatana) => { // 应用第二个自定义参数!
expect(powerfulGoldKatana.material).to.eql("gold");
expect(powerfulGoldKatana.damage).to.eql(100);
});
goldKatanaProvider(10).then((notSoPowerfulGoldKatana) => {
expect(notSoPowerfulGoldKatana.material).to.eql("gold");
expect(notSoPowerfulGoldKatana.damage).to.eql(10);
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
单例 provider
虽然Provider
总是以单例形式被注入,但是您可以控制它的返回值是使用单例还是瞬态作用域(transient scope):
let container = new Container();
interface Warrior {
level: number;
}
@injectable()
class Ninja implements Warrior {
public level: number;
public constructor() {
this.level = 0;
}
}
type WarriorProvider = (level: number) => Promise<Warrior>;
container.bind<Warrior>("Warrior").to(Ninja).inSingletonScope(); // Value is singleton!
container.bind<WarriorProvider>("WarriorProvider").toProvider<Warrior>((context) => {
return (increaseLevel: number) => {
return new Promise<Warrior>((resolve) => {
setTimeout(() => {
let warrior = context.container.get<Warrior>("Warrior"); // Get singleton!
warrior.level += increaseLevel;
resolve(warrior);
}, 100);
});
};
});
let warriorProvider = container.get<WarriorProvider>("WarriorProvider");
warriorProvider(10).then((warrior) => {
expect(warrior.level).to.eql(10);
});
warriorProvider(10).then((warrior2) => {
expect(warrior.level).to.eql(20);
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
Provider 默认值
下面的函数可以帮助您在注入provider
时提供一个默认值:
function valueOrDefault<T>(provider: () => Promise<T>, defaultValue: T) {
return new Promise<T>((resolve, reject) => {
provider().then((value) => {
resolve(value);
}).catch(() => {
resolve(defaultValue);
});
});
}
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
下面来展示一下valueOrDefault
函数的使用方式:
@injectable()
class Ninja {
public level: number;
public rank: string;
public constructor() {
this.level = 0;
this.rank = "Ninja";
}
public train(): Promise<number> {
return new Promise<number>((resolve) => {
setTimeout(() => {
this.level += 10;
resolve(this.level);
}, 100);
});
}
}
@injectable()
class NinjaMaster {
public rank: string;
public constructor() {
this.rank = "NinjaMaster";
}
}
type NinjaMasterProvider = () => Promise<NinjaMaster>;
let container = new Container();
container.bind<Ninja>("Ninja").to(Ninja).inSingletonScope();
container.bind<NinjaMasterProvider>("NinjaMasterProvider").toProvider((context) => {
return () => {
return new Promise<NinjaMaster>((resolve, reject) => {
let ninja = context.container.get<Ninja>("Ninja");
ninja.train().then((level) => {
if (level >= 20) {
resolve(new NinjaMaster());
} else {
reject("Not enough training");
}
});
});
};
});
let ninjaMasterProvider = container.get<NinjaMasterProvider>("NinjaMasterProvider");
valueOrDefault(ninjaMasterProvider, { rank: "DefaultNinjaMaster" }).then((ninjaMaster) => {
// 这里使用了默认值因为 provider 被 rejected 了 (忍者等级还不到20级)
expect(ninjaMaster.rank).to.eql("DefaultNinjaMaster");
});
valueOrDefault(ninjaMasterProvider, { rank: "DefaultNinjaMaster" }).then((ninjaMaster) => {
// 传入的 NinjaMaster 起作用了,因为忍者已经大于20级了
expect(ninjaMaster.rank).to.eql("NinjaMaster");
done();
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58