-
mhtml Rx 이해하기 - Ajax 호출시 경험web/mhtml 2021. 10. 27. 23:28
문제
다음 코드는 유효한 url 을 호출하였음에도 브라우저 콘솔에서 에러 메시지를 볼 수 있다.
import mhtml._ import mhtml.future.syntax.FutureToRxSyntax import org.scalajs.dom import org.scalajs.dom.ext.Ajax import scala.concurrent.ExecutionContext.Implicits.global import scala.util.Success object MHtmlTest { def view(): Unit = { val url: String = "https://jsonplaceholder.typicode.com/todos/1" val response: Rx[List[String]] = Ajax.get(url).toRx.map { case Some(Success(xhr)) => List(xhr.responseText) case _ => List.empty[String] } val text: Rx[Option[String]] = response.map(_.headOption) val content = <div>{text}</div> mount(dom.document.getElementById("main_content"), content) } }
에러 메시지는 다음과 같았다.
Throwables.scala:18 Uncaught java.util.NoSuchElementException: head of empty list at $c_sci_Nil$.head__E (http://localhost:9000/versionedAssets/client-fastopt.js:45271:44) at $c_sci_Nil$.head__O (http://localhost:9000/versionedAssets/client-fastopt.js:45300:8) at http://localhost:9000/versionedAssets/client-fastopt.js:2879:22 at $c_sjsr_AnonFunction1.apply__O__O (http://localhost:9000/versionedAssets/client-fastopt.js:19303:43) at http://localhost:9000/versionedAssets/client-fastopt.js:7635:34 at $c_sjsr_AnonFunction1.apply__O__O (http://localhost:9000/versionedAssets/client-fastopt.js:19303:43) at http://localhost:9000/versionedAssets/client-fastopt.js:7635:18 at $c_sjsr_AnonFunction1.apply__O__O (http://localhost:9000/versionedAssets/client-fastopt.js:19303:43) at $c_Lmhtml_Var.foreach__F1__F0 (http://localhost:9000/versionedAssets/client-fastopt.js:13400:19) at $c_Lmhtml_Rx$.run__Lmhtml_Rx__F1__F0 (http://localhost:9000/versionedAssets/client-fastopt.js:7834:18)
Why?
설명
mhtml 의 Rx 는 async 로 toRx 메서드 구현을 살펴보면 아래처럼 되어있다.
object Utils { /** Convert a `Future` to a `Rx` */ def futureToRx[T](f: Future[T])(implicit ec: ExecutionContext): Rx[Option[Try[T]]] = { val result: Var[Option[Try[T]]] = Var(None) f.onComplete(x => result := Some(x)) result } } object syntax { implicit class FutureToRxSyntax[T](f: Future[T]) { def toRx(implicit ec: ExecutionContext): Rx[Option[Try[T]]] = Utils.futureToRx(f) } }
따라서 즉시 Var(None) 을 리턴하고, 계산이 다 되면 이후에 다시 한번 Some(x) 가 리턴되어 dom 을 다시 그리게 된다.
그런데 작성된 코드에서는 Var(None) 을 리턴 받았을 때 제대로 처리하지 못하게 되어있다.
val text: Rx[String] = response.map(_.head)
이 부분을 아래와 같이 고쳐야 한다.
val text: Rx[Option[String]] = response.map(_.headOption)
Rx 가 async 로 바로 리턴되고, 이후에 제대로된 응답을 받으면 다시 그린다는 것을 주의해야 한다.
아니면 dropIf 나 keepIf 함수를 사용해 바로 리턴되는 값은 필터링해 전파되는 것을 막는 것이 좋을 것 같다.
'web > mhtml' 카테고리의 다른 글
javascript callback 처리 하기 - radio button (0) 2022.01.03 impure run 사용하기 (0) 2021.10.28 mhtml 에서 imitate 로 Var 값에 Rx 복사하기 (0) 2021.10.25 javascript callback 처리 하기 - checkbox (0) 2021.10.25 javascript callback 처리 하기 - dropdown (0) 2021.10.25