angular useFactory return 模块中的异步函数

angular useFactory return async Function in module

我想弄清楚如何在 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 { }

问题是它解析了异步函数,但在返回它之前没有解析。我在 Whosebug 上看到一些其他帖子来解决这个问题,但他们最终遗漏了函数的 async 部分。你不能有一个不在异步函数中的等待,所以我在这里忘记了。

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

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

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

您不能在不支持的依赖项注入中拥有异步工厂函数。有一个内置功能可以帮助您解决此问题,称为应用程序初始化程序。您可以使用内置 APP_INITIALIZER token. This token requires a factory that will return a function that will be called as the application initializer and it can return a promise. This application initializers are called at the start of the application and the application does not start until all finish. For your case I think this is ok since you read some kind of configuration. Unfortunately there is no good official documentation on this that I'm aware of. If you search you will find some articles on this topic. Here is a link to another 在依赖注入中注册应用程序初始值设定项。 要在你的情况下使用这种方法,我认为最好创建一个服务来进行初始化然后保存值。

@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));
  }
}

如您所见,我还在 promise 中添加了延迟,以模拟它稍后完成。 现在让我们也更改您的模块以使用应用程序初始化程序。

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,您可以在其中看到它的实际效果。