在ReasonML中从Js.Promise转换为`reason-promise`

问题描述

我遇到的情况是,图书馆使用reason-promise作为认的一个分支,而不是另一个。我发现很难从一个分支切换到另一个分支,因为在我的一生中,我无法弄清楚如何使用理性承诺。我对Js.Promise的了解不是很好,但这不重要。

有问题的图书馆为reason-apollo-client。该分支还有很多其他改进,包括reason-promise作为认的promise实现。该分支是next branch

通过示例,可以在reason-promise-question处找到一个Js.Promise函数,该函数可以为我获取当前的令牌值。它具有以下类型:

unit => Js.Promise.t(
  Js.Nullable.t(string)
)

功能可以在Tokens中找到,并在下面复制。这是一个函数,没有绑定。关键是要了解如何进行编译。

[@bs.val] [@bs.scope "localStorage"]
external setItem: (string,string) => unit = "setItem";
let setUserToken: string => Js.Promise.t(unit) =
  token => Js.Promise.resolve(setItem("auth",token));

[@bs.val] [@bs.scope "localStorage"]
external getItem: string => Js.Nullable.t(string) = "getItem";
let getUserToken: unit => Js.Promise.t(Js.Nullable.t(string)) =
  () => Js.Promise.resolve(getItem("auth"));

let setTempuserToken: string => Js.Promise.t(unit) =
  _ => Js.Promise.resolve();

let getTempuserToken: unit => Js.Promise.t(Js.Nullable.t(string)) =
  () => Js.Promise.resolve(Js.Nullable.undefined);

当我在创建reason-promise apollo/client时尝试与authlink配合使用时,出现以下错误

unit => Js.Promise.t(
  Js.Nullable.t(string)
)
Error: This expression has type
         Js.Promise.t(Js.Json.t) = Js.Promise.t(Js.Json.t)
       but an expression was expected of type
         Promise.t(Js.Json.t) = Promise.rejectable(Js.Json.t,Promise.never)

这是authlink函数

let authLink =
  ApolloClient.Link.ContextLink.makeAsync((~operation as _,~prevContext as ctx) => {
    Tokens.getUserToken()
    ->Js.Promise.then_(
        token => {
          switch (token->Js.Nullable.toOption) {
          | None =>
            Tokens.getTempuserToken()
            ->Js.Promise.then_(
                token => Js.Promise.resolve(Js.Nullable.toOption(token)),_,)
          | Some(token) => Js.Promise.resolve(Some(token))
          }
        },)
    ->Js.Promise.then_(
        fun
        | None => Js.Promise.resolve(Js.Json.null)
        | Some(token) => {
            Js.Promise.resolve(
              [%raw
                {| (context,token) => ({
                headers: {
                  ...ctx.headers,authorization: `Bearer ${token}`
                }
              }) |}
              ](
                ctx,token,),);
          },)
  });

我们如何将其转换为原因承诺?请随心所欲地欺骗自己。

谢谢你。

解决方法

您应该能够将原版 Js.Promise.t 转换为 Promise.t

首先,您必须将 Js.Promise.t 转换为 Promise.Js.t。这可以通过

let myIntermediatePromise = myJsPromise |>  Promise.Js.fromBsPromise

额外的 Promise.Js.t 类型存在的原因是 Js.Promise.tPromise.t 之间的错误处理原理不同。后者使用 Belt.Result 模块处理错误(如 https://github.com/aantron/promise#handling-errors-with-result 所示),而前者使用拒绝(通常使用 catch (在 JavaScript 中)或 catch_ (合理))。 Promise.Js.t 的中间产品封装了与 JavaScript 承诺相同的理念。

为了将中间产品转换为最终的 Promise.t,您需要明确指出当/如果中间承诺被拒绝时会发生什么。这可以通过几种不同的方式来完成,但作为一个例子,你可以这样做:

let myFinalPromise = myIntermediatePromise |> Promise.Js.toResult

这会将您原来的 Js.Promise.t('a) 转换为 Promise.t(Result('a,Js.Promise.error))

如果您想进一步转换为 Promise.t('a),您必须明确处理可能出现的错误。

有关详细信息,请参阅 https://github.com/aantron/promise#advanced-rejection

请注意,从那以后,阿波罗似乎已经开始使用普通 Promise (https://github.com/reasonml-community/reason-apollo-client/pull/57)。