27

I tried to use Promises and Futures in Scala.js. Promise works, as soon as it comes to Futures I get warnings and errors.

Try:

val p1 = Promise[Int]
val f1: Future[Int] = p1.future
val p2 = Promise[Int]
val f2: Future[Int] = p2.future

val res1 =  for {
   v1 <- f1
   v2 <- f2
} yield v1 + v2


val res2 = f1.flatMap(x => f2.map(y => x + y))



res1 onSuccess {
  case x: Int => g.console.log(x);

}

res2 onSuccess {
  case x: Int => g.console.log(x);

}

// callback in dom, using ScalaTags
// div(`class` := "btn  btn-default", `type` := "button", onclick := click(1, p1))
def click(i: Int, p: Promise[Int])(x: dom.MouseEvent): Unit = {
  g.console.log(i);
  try {
    p success i
  }
  catch {
    case x: Throwable => println("again")
  }
}

f1 onSuccess {
  case x: Int => 1

}

And I get in sbt fastOptJs:

[warn] Referring to non-existent class jl_Thread$UncaughtExceptionHandler
[warn]   called from s_concurrent_impl_ExecutionContextImpl.init___ju_concurrent_Executor__F1
[warn]   called from s_concurrent_impl_ExecutionContextImpl$.fromExecutor__ju_concurrent_Executor__F1__s_concurrent_impl_ExecutionContextImpl
[warn]   called from s_concurrent_ExecutionContext$Implicits$.global$lzycompute__p1__s_concurrent_ExecutionContextExecutor
[warn]   called from s_concurrent_ExecutionContext$Implicits$.global__s_concurrent_ExecutionContextExecutor
[warn]   called from Lexample_H2$class.Lexample_H2$class__$init$__Lexample_H2__V
[warn] 

And I get in the browser:

uncaught exception: java.lang.RuntimeException: System.getProperty() not implemented

What is missing/unimplemented? How can I implement it? Is there a workaround? How can I implement an ExecutionContext that is makes sense to handle Events withing the browser?

Martin Tournoij
  • 26,737
  • 24
  • 105
  • 146

1 Answers1

34

Since Scala.js 0.6.0, the standard global ExecutionContext of Scala is available in Scala.js. You can import it with

import scala.concurrent.ExecutionContext.Implicits.global

// now you get to play with Futures

In Scala.js, it is an alias to scala.scalajs.concurrent.JSExecutionContext.Implicits.queue. This execution context enqueues jobs in the standard JavaScript event loop.

Note that tasks are executed asynchronously, but not in parallel, since JavaScript has no notion of parallelism per se. If parallelism is required, Web Workers need to be used, but those do not provide the shared-memory model required by Futures as such.

Old answer applying to Scala.js < 0.6.0

There are 2 existing and working ExecutionContexts in scala.scalajs.concurrent.JSExecutionContext, with implicit versions in the inner object Implicits. Simply import the one that makes sense for you (probably queue, the other one not being actually asynchronous).

import scala.scalajs.concurrent.JSExecutionContext.Implicits.queue

// now you get to play with Futures
sjrd
  • 21,805
  • 2
  • 61
  • 91
  • After a short research, the `queue` is implemented either using [promises](https://www.promisejs.org/) or using [timeouts](http://www.w3schools.com/jsref/met_win_settimeout.asp) for old browsers not supporting promises. – Suma Jan 06 '17 at 12:12
  • Note: `queue` is asynchronous in the sense the code is executed later (using then on a resolved Promise or setTimeout), but the code does not run in parallel. For real "parallel" (concurrent) tasks you need Web Workers, e.g using a library from github.com/nolanlawson/promise-worker. Or am I wrong here? – Suma Jan 06 '17 at 13:12
  • @Suma You're right. There's no such thing as shared-memory parallelism in JavaScript, so `Promise`s and `Future`s do not execute in parallel. If parallelism is required, you need to use Web Workers, but you lose shared memory, which fundamentally changes how things work in its own right. – sjrd Jan 06 '17 at 14:17