【问题标题】:fp-ts How to Handle Async operations within pipefp-ts 如何处理管道内的异步操作
【发布时间】:2021-10-29 16:22:16
【问题描述】:

我正在学习 fp-ts,我想知道如何更好地组织我的函数以避免嵌套折叠。我在网上看到的所有示例都有一个很好的流线型 pipe 函数调用,但我不知道如何避免嵌套折叠。

一些上下文 - 概括地说,此代码的目的是创建一个Location,如果成功,则创建一个Station。如果任一操作失败,则将适当的错误返回给调用者。如果一切正常,返回 201。

public async initialize(
    @requestParam('site') site: string,
    @request() req: Request,
    @response() res: Response
  ) {
    //use the same value for now
    const nameAndPublicId = LocationService.retailOnlineLocationName(site);
    
    const location: E.Either<ApiError, LocationDTO> = await this.locationService.createLocation(
      site,
      nameAndPublicId,
      nameAndPublicId
    );

    const stationName: string = StationService.retailOnlineStationName(site);

    pipe(
      location,
      E.fold(
        (err: ApiError) => ConfigController.respondWithError(err, res),
        async (loc: LocationDTO) => {
          pipe(
            await this.stationService.createStation(site, stationName, loc.id),
            E.fold(
              (err: ApiError) => ConfigController.respondWithError(err, res),
              (_: StationDTO) => res.status(201).send()
            )
          );
        }
      )
    );
  }

  static respondWithError(err: ApiError, res: Response) {
    res.status(err.statusCode).json(err);
  }

【问题讨论】:

    标签: typescript fp-ts


    【解决方案1】:

    假设我们正在使用Promise,代码会是什么样的?您将使用.then 链接所有好的案例处理代码,并且只附加一个带有最终.catch 的坏案例处理程序。

    public async initialize(
      @requestParam('site') site: string,
      @request() req: Request,
      @response() res: Response
    ) {
      const stationName: string = StationService.retailOnlineStationName(site);
    
      const nameAndPublicId = LocationService.retailOnlineLocationName(site);
      
      // for illustration purpose, we suppose here
      // the service returns a Promise of actual value
      // instead of Promise of Either
      await this.locationService.createLocation(
        site,
        nameAndPublicId,
        nameAndPublicId
      ).then((loc: LocationDTO) => {
        return this.stationService.createStation(site, stationName, loc.id)
      }).then((_: StationDTO) => {
        res.status(201).send()
      }).catch(err => {
        ConfigController.respondWithError(err, res),
      })
    }
    

    fp 版本应该具有相同的结构,只是类型不同。我们可以使用TaskEither 类型来模拟Promise

    public async initialize(
      @requestParam('site') site: string,
      @request() req: Request,
      @response() res: Response
    ) {
      const stationName: string = StationService.retailOnlineStationName(site);
    
      const nameAndPublicId = LocationService.retailOnlineLocationName(site);
      
      // here the service shall return Promise of Either
      const createLocationTask = () => this.locationService.createLocation(
        site,
        nameAndPublicId,
        nameAndPublicId
      )
    
      const chainedTask = pipe(
        createLocationTask,
        TE.fold(
          TE.throwError, // pass through error
          (loc: LocationDTO) => async () => stationService.createStation(site, stationName, loc.id),
        ),
        TE.fold(
          // catch error
          (err: ApiError) => async () => ConfigController.respondWithError(err, res),
          (_: StationDTO) => async () => { res.status(201).send() },
        )
      )
    
      await chainedTask()
    }
    

    附件是一个带有存根的 ts playground 演示。

    TS Playground

    【讨论】:

    • 谢谢,这很有帮助。我不知道TE.throwError;那是一个有用的结构。我仍在努力解决的一件事是,为什么我们需要将第一部分转换为返回承诺的函数。即,为什么我们不能只使用服务调用而不是 createLocationTask ?相关,我注意到chainedTask 中没有awaits ......这样我们就可以在整个管道中处理promise - 最后是await 整个chainedTask
    • 第一部分,因为这是你在使用pipe函数之前需要签署的合同。 Pipe 要求管道中的所有内容都属于同一类型。由于下游处理程序ReturnType&lt;typeof TE.fold&gt; 指定它接受类型为TaskEither 的参数等于() =&gt; Promise&lt;Either&gt;,因此我们需要将服务调用转换为这种类型,因此createLocationTask
    • 第二部分,我认为你或多或少地明白了这一点。澄清一下,插入一些 await 没有害处,但也无济于事。 Await 仅在您想“解包”一个 Promise 时有用,但我们这里没有用例。
    猜你喜欢
    • 2020-04-18
    • 1970-01-01
    • 2022-08-14
    • 2021-08-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-25
    • 2019-10-16
    相关资源
    最近更新 更多