我正在尝试为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
为空,并且定义了response
和body
,反之亦然。
在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]
,但这会从Some(null)
和.toOption
返回js.JavaScriptException | Null
,但我似乎只能将其转换为Option[js.JavaScriptException | Null]
。
与undefined
不同,Scala.js没有为您提供处理null
的特殊工具。
这是因为在Scala中,所有内容都是可为空的(我们中的许多人不喜欢这个事实,包括我自己,但这是不同的讨论。)>
因此,我们必须争论立面does
在使用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
。