angular - angular useFactory在模块中返回异步函数
问题描述
我试图弄清楚如何在 Angular 11 中使用useFactory作为异步函数。现在我有这个:
import { ApolloClientOptions } from 'apollo-client';
import { FirebaseService } from './firebase.service';
// other imports here...
export async function createApollo(httpLink: HttpLink, fs: FirebaseService): Promise<ApolloClientOptions<any>> {
const token = await fs.getToken();
const getHeaders = async () => {
return {
"X-Auth-Token": token,
};
};
// functions has more content here...
return Promise.resolve({
link: errorLink.concat(link),
cache: new InMemoryCache(),
});
}
@NgModule({
imports: [HttpLinkModule],
providers: [
{
provide: APOLLO_OPTIONS,
useFactory: createApollo,
deps: [HttpLink, FirebaseService],
},
],
})
export class DgraphModule { }
问题是它解决了异步函数,但不是在返回它之前。我在 StackOverFlow 上看到了一些其他帖子来解决这个问题,但他们最终忽略了函数的异步部分。你不能有一个不在异步函数中的等待,所以我在这里没有注意到。
如果该函数不是异步函数,您也不能将异步函数放在异步函数中......那我该怎么办?
更新:2/11/21 - 据此,有一种方法可以做到这一点PlatformBrowserDynamic()
,但我不明白如何在我的模块中实现它。
更新:2/13/21这是 codeandbox.io 的链接-忽略缺少 html 或工作端点,但您可以查看模块并将其更改为async
函数以查看是否存在Invariant Violation错误。---> 确保查看代码和沙盒控制台是否有错误。
解决方案
您不能在不支持的依赖注入中拥有异步工厂函数。有一个内置功能可以帮助您解决此问题,称为应用程序初始化程序。您可以使用内置的APP_INITIALIZER令牌在依赖注入中注册应用程序初始化程序。此令牌需要一个工厂,该工厂将返回一个函数,该函数将被称为应用程序初始化程序,并且它可以返回一个承诺。此应用程序初始化程序在应用程序开始时被调用,并且应用程序在全部完成之前不会启动。对于您的情况,我认为这没关系,因为您阅读了某种配置。不幸的是,我知道没有很好的官方文档。如果你搜索你会发现一些关于这个主题的文章。这是另一个链接解释它的堆栈溢出问题。要在您的情况下使用这种方法,我认为最好创建一个进行初始化然后保存值的服务。
@Injectable()
export class ApolloOptionsService {
public apolloOptions: any;
constructor(private httpLink: HttpLink) {}
public createApollo() {
const token = "";
const getHeaders = async () => {
return {
"X-Auth-Token": token
};
};
const http = ApolloLink.from([
setContext(async () => {
return {
headers: await getHeaders()
};
}),
this.httpLink.create({
uri: `https://${endpoint}`
})
]);
// Create a WebSocket link:
const ws = new WebSocketLink({
uri: `wss://${endpoint}`,
options: {
reconnect: true,
connectionParams: async () => {
return await getHeaders();
}
}
});
const link = split(
// split based on operation type
({ query }) => {
const definition = getMainDefinition(query);
return (
definition.kind === "OperationDefinition" &&
definition.operation === "subscription"
);
},
ws,
http
);
return new Promise((resolve) => {
setTimeout(() => {
resolve({
link: link,
cache: new InMemoryCache()
});
}, 5000);
}).then((apoloOptions) => (this.apolloOptions = apoloOptions));
}
}
正如你所看到的,我还在承诺中添加了一个延迟,以模拟它稍后完成。现在让我们也更改您的模块以使用应用程序初始化程序。
export function createApollo(apolloOptionsService: ApolloOptionsService) {
return () => apolloOptionsService.createApollo();
}
export function getApolloOptions(apolloOptionsService: ApolloOptionsService) {
return apolloOptionsService.apolloOptions;
}
@NgModule({
imports: [HttpLinkModule],
providers: [
ApolloOptionsService,
{
provide: APP_INITIALIZER,
useFactory: createApollo,
deps: [ApolloOptionsService],
multi: true
},
{
provide: APOLLO_OPTIONS,
useFactory: getApolloOptions,
deps: [ApolloOptionsService]
}
]
})
export class GraphQLModule {}
如您所见,我们使用一个工厂函数来创建应用程序初始化函数,该函数在应用程序初始化时被调用。需要另一个工厂函数来从服务中读取初始化值并将其作为APOLLO_OPTIONS
令牌提供。因为初始化程序在应用程序启动之前运行,所以值在使用之前就准备好了。
我还创建了您的代码框的一个分支,您可以在其中看到它的实际效果。
推荐阅读
- tfs - 使用 VSTS 符号服务器的 TFS 2018 更新 2 失败
- angular - Angular 6:如何根据 mat-nav-list 选定项在单独的部分中呈现注入数据?
- html - 将滑块值从 html 表单导入到烧瓶应用程序
- javascript - jQuery插件功能永远无法实现
- mysql - 如何在 node.js 中对 MySQL 返回的结果进行嵌套
- wpf - 如何获取 LiveCharts LabelPoint 值?
- exe - 如何使脚本在 Windows 中可执行
- angular - 无法使用 Ionic 3 与 EventEmitters 进行组件通信
- php - varchar 的 MySQL 错误顺序
- macos - 在 Mac OSX 上构建包时遇到问题