【问题标题】:angular useFactory return async Function in moduleangular useFactory在模块中返回异步函数
【发布时间】:2021-02-15 06:10:17
【问题描述】:

我正在尝试弄清楚如何在 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 上看到了一些其他帖子来解决这个问题,但他们最终忽略了函数的 async 部分。你不能有一个不在异步函数中的等待,所以我在这里没有注意到。

如果该函数不是异步函数,您也不能将异步函数放在异步函数中......那我该怎么办?

更新:2/11/21 - 根据this 的说法,PlatformBrowserDynamic() 可以做到这一点,但我不明白如何在我的模块中实现它。 p>

更新:21 年 2 月 13 日 这是指向 codeandbox.io 的链接 - 忽略缺少 html 或工作端点,但您可以查看模块并将其更改为 async 函数查看是否存在 Invariant Violation 错误。 ---> 确保查看代码和沙盒控制台是否有错误。

【问题讨论】:

  • 这个函数返回一个promise,所以在实现中你应该返回一个promise。然后,您可以在该承诺中包含您的逻辑,该逻辑应在最后解决该承诺。所以类似 return new Promise(async function (resolve) { #some stuff here you await then call resolve("answer"'); })
  • 我刚刚返回了一个已解决的 Promise,我收到了相同的错误 Invariant Violation: To initialize Apollo Client, you must specify a 'cache' property in the options object.,因为它返回的是承诺而不是值。一切都可以在没有异步的情况下工作,但是我需要异步才能使我的令牌标头工作...查看更新的完整代码...
  • 我对 apollo 客户端不是很熟悉。您希望如何使用提供程序 APOLLO_OPTIONS?它应该只是一个 POJO js 对象吗?
  • 在这种情况下,它只是 Apollo 的选项(可以是任何东西,但我使用导入更新了代码),但关键是如何将 async 与 @ 一起使用987654327@.

标签: angular async-await angular-module angular-providers angular11


【解决方案1】:

在不支持的依赖注入中不能有异步工厂函数。有一个内置功能可以帮助您解决此问题,称为应用程序初始化程序。您可以使用内置的 APP_INITIALIZER 令牌在依赖注入中注册应用程序初始化程序。此令牌需要一个工厂,该工厂将返回一个函数,该函数将被称为应用程序初始化程序,并且它可以返回一个承诺。此应用程序初始化程序在应用程序开始时被调用,并且应用程序在全部完成之前不会启动。对于您的情况,我认为这没关系,因为您阅读了某种配置。不幸的是,我知道没有很好的官方文档。如果你搜索你会发现一些关于这个主题的文章。这是另一个stack overflow question that explains it 的链接。 要在您的情况下使用这种方法,我认为最好创建一个进行初始化然后保存值的服务。

@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 令牌提供。因为初始化程序在应用程序启动之前运行,所以值在使用之前就准备好了。

我还创建了一个fork of your codesandbox,您可以在其中看到这一点。

【讨论】:

    猜你喜欢
    • 2018-11-07
    • 2013-05-15
    • 1970-01-01
    • 2017-10-24
    • 1970-01-01
    • 2021-02-23
    • 2023-04-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多