【问题标题】:How to deal with nullable values in scala.js facades?如何处理 scala.js 外观中的可为空值?
【发布时间】:2020-02-23 03:44:01
【问题描述】:

我正在尝试为 request 库编写一个 Scalajs 外观,它有一个使用回调模式的方法:

request('http://www.google.com', function (error, response, body) {
  console.log('error:', error); // Print the error if one occurred
  console.log('statusCode:', response && response.statusCode); // Print the response status code if a response was received
  console.log('body:', body); // Print the HTML for the Google homepage.
});

在此模式中,error 为 null,responsebody 已定义,反之亦然。

在 ScalaJS 外观中反映这种模式的最佳方式是什么?我能想到的最好的方法是:

@js.native
@JSImport("request", JSImport.Default)
object Request extends js.Object {
  def apply[A](uri: String,
               requestConfig: js.Object,
               callback: js.Function2[js.JavaScriptException, Response, A]): Unit = js.native
}

执行该方法后,我使用Option 匹配正确的大小写:

Request(url, RequestConfig(queryString, headers), (error, response) => {
  (Option(error), Option(response)) match {
    case (Some(err), _) => // handle error
    case (_, Some(res)) => // handle success
    case (None, None) => // This will only happen if there is a bug in the request library
  }
})

我不喜欢这样,因为 1) 我必须为 (None, None) 编写一个不必要的匹配项,或者忽略非详尽的匹配警告,以及 2) 外观没有准确地描述类型。

我也尝试过使用js.UndefOr[js.JavaScriptException],但这会从.toOptionjs.JavaScriptException | Null 返回Some(null),但我似乎只能将其转换为Option[js.JavaScriptException | Null]

【问题讨论】:

  • 也许将您的包装输入为Either[JavaScriptException, Response]?另外,我不知道 Scala.js 中Future 的状态,但如果可能,我会尽量避免回调并执行def apply(uri, config): Future[Response],如果出现异常,Future 将失败。然后变成Request(uri, config).map(response => turnIntoA)

标签: scala.js


【解决方案1】:

undefined 不同,Scala.js 没有为您提供处理null 的特殊工具。

这是因为在 Scala 中一切都是可以为空的(我们中的许多人都不喜欢这个事实,包括我自己,但这是一个不同的讨论)。

因此,我们必须证明外观确实使用 Scala / Scala.js 类型系统尽可能准确地描述了类型。

如果您需要经常使用它,@Thilo 建议的包装器确实是您的最佳选择:

object RichRequest {
  def apply(uri: String, req: RequestConfig): Future[Response] = {
    val p = Promise[Response]()
    Request(uri, req, (error, response) => {
      if (error != null) p.failure(error)
      else p.success(response)
    })
    p.future
  }
}

或者,如果您想保持基于 API 回调,请考虑使用 Try

请注意,如果您想走这条路,请考虑使用 request-promise-native 开箱即用(使用 JavaScript 承诺)。

所以你的外观会变成:

@js.native
@JSImport("request-promise-native", JSImport.Default)
object Request extends js.Object {
  def apply(uri: String, requestConfig: js.Object): js.Promise[Response] = js.native
}

还有通话地点:

Request(url, RequestConfig(...)).toFuture

【讨论】:

    猜你喜欢
    • 2018-08-29
    • 2017-05-18
    • 2017-05-26
    • 1970-01-01
    • 2015-04-17
    • 2023-01-26
    • 1970-01-01
    • 2018-02-20
    • 1970-01-01
    相关资源
    最近更新 更多