【发布时间】:2017-06-09 15:32:14
【问题描述】:
我正在尝试为缓存服务创建服务工厂。主要要求是每次可以使用不同的字符串实例化单个服务。
最终结果将有多个缓存服务,每个服务都由唯一的databaseName 定义。每个缓存可以有一个或多个 stores 也由唯一的storeName 定义。其他服务将能够使用这些商店:
mainCache = new Cache('main')
├── userStore = new Store(mainCache, 'user')
│ ├── userService
│ └── authenticationService
│
└── taskStore = new Store(mainCache, 'task')
└── taskService
fooCache = new Cache('foo')
└── barStore = new Store(otherCache, 'bar')
我当前的实现如下所示:
//indexeddb-cache.ts
import { Injectable } from '@angular/core';
@Injectable()
export class IndexedDBCache {
constructor(
protected databaseName : string
) {}
}
// indexeddb-store.ts
import { Injectable } from '@angular/core';
import { IndexedDBCache } from './indexeddb-cache';
@Injectable()
export class IndexedDBStore {
constructor(
protected database : IndexedDBCache,
protected storeName : string
) {}
}
服务被分解:
// test-api.cache.factory.ts
import { IndexedDBCache } from '../indexeddb-cache/indexeddb-cache';
import { IndexedDBStore } from '../indexeddb-cache/indexeddb-store';
// factory functions for FactoryProviders as exports instead of inline:
// https://github.com/rangle/angular-2-aot-sandbox#func-in-providers-usefactory-top
export function mainIndexedDBCacheFactory() { return new IndexedDBCache('main'); }
export function userIndexedDBStoreFactory(testIndexedDBCache: IndexedDBCache) { return new IndexedDBStore(testIndexedDBCache, 'user'); }
export function taskIndexedDBStoreFactory(testIndexedDBCache: IndexedDBCache) { return new IndexedDBStore(testIndexedDBCache, 'task'); }
然后提供:
// test-api.cache.ts
import { InjectionToken, Provider } from '@angular/core';
import { IndexedDBCache } from '../indexeddb-cache/indexeddb-cache';
import { IndexedDBStore } from '../indexeddb-cache/indexeddb-store';
import { mainIndexedDBCacheFactory,
taskIndexedDBStoreFactory,
userIndexedDBStoreFactory } from './test-api.cache.factory';
// Caches
export const mainIndexedDBCache = new InjectionToken<IndexedDBCache>('mainIndexedDBCache');
export let mainIndexedDBCacheProvider : Provider = {
provide: mainIndexedDBCache,
useFactory: mainIndexedDBCacheFactory
};
// Stores
export const userIndexedDBStore = new InjectionToken<IndexedDBStore>('userIndexedDBStore');
export let userIndexedDBStoreProvider : Provider = {
provide: userIndexedDBStore, deps: [mainIndexedDBCache],
useFactory: userIndexedDBStoreFactory
};
export const taskIndexedDBStore = new InjectionToken<IndexedDBStore>('taskIndexedDBStore');
export let taskIndexedDBStoreProvider : Provider = {
provide: taskIndexedDBStore, deps: [mainIndexedDBCache],
useFactory: taskIndexedDBStoreFactory
};
在主模块中声明:
// test-api-module.ts
import { NgModule, ModuleWithProviders } from '@angular/core';
import { mainIndexedDBCacheProvider,
taskIndexedDBStoreProvider,
userIndexedDBStoreProvider } from './test-api.cache';
@NgModule({
imports: [], declarations: [], exports: []
})
export class TestAPIModule {
static forRoot(): ModuleWithProviders {
return {
ngModule: TestAPIModule,
providers: [
mainIndexedDBCacheProvider,
userIndexedDBStoreProvider,
taskIndexedDBStoreProvider
]
};
}
}
最后用在一个服务中:
//user-service/user.service.ts
import { Inject, Injectable } from '@angular/core';
import { IndexedDBStore } from '../../indexeddb-cache/indexeddb-store';
import { userIndexedDBStore } from '../test-api.cache';
@Injectable()
export class UserService {
constructor(
@Inject(userIndexedDBStore) protected cache : IndexedDBStore
) {}
}
使用 JIT 编译器时一切正常。当我尝试进行 AoT 编译时,我开始收到 Warning: Can't resolve all parameters for x in y: (?). This will become an error in Angular v5.x 用于缓存和存储服务的字符串参数。
我之前在这个问题中详细说明了我的问题:Tokenizing for AoT compilation。现在看起来使用字符串作为 @Injectable() 的参数对于 AoT 编译器来说是完全不可能的。有没有其他方法可以为使用字符串初始化的服务创建工厂,正如我所描述的那样?
我在this repository 中创建了一个可行的示例。检查aot 分支和npm install 后跟npm run build.prod.rollup.aot 应该可以这样工作。
【问题讨论】:
-
那么 'x in y' 中的 x 和 y 是什么?..
-
@estus
IndexedDBCache和indexeddb-cache.ts的位置。 -
我不确定
protected storeName : string应该如何工作。没有string提供者。它不是特定于 AoT 的功能,我希望它在 JiT 中也会失败,因为它是错误的。如果你只使用IndexedDBCache作为new IndexedDBCache,它不应该是Injectable。尝试从构造函数中不执行 DI 的类中删除Injectable并检查它是否适合您。 -
@estus 它在 angularjs 中是这样工作的,在 JIT 中也能正常工作。在本例中,它甚至可以在 AoT 中编译,但会显示警告。核心思想是我可以从一个定义(>工厂)创建多个商店,并且多个组件可以与同一个商店实例对话。如果这是错误的方法,您能否举例说明该结构的正确方法?
-
Angular(2 和更高版本)不是 AngularJS,它们是橘子和苹果。只需从 IndexedDBCache 和 IndexedDBStore 中删除 @Injectable 即可。它不是可注入的,因为构造函数参数不是正确的服务。请参阅 Injectable decorator stackoverflow.com/a/39029435/3731501 的说明
标签: angular dependency-injection aot