Scala standard library implementation for Scala.js, providing core library functionality for Scala code compiled to JavaScript
—
Asynchronous programming utilities adapted for JavaScript's event loop and single-threaded execution model, providing familiar Scala concurrent programming APIs while working within JavaScript's constraints.
Core abstraction for executing asynchronous operations, adapted for JavaScript's single-threaded event loop model.
/**
* Represents a context where asynchronous operations can be executed
* In JavaScript, this typically uses setTimeout, Promise.resolve, or similar mechanisms
*/
trait ExecutionContext {
/** Execute the given runnable asynchronously */
def execute(runnable: Runnable): Unit
/** Report uncaught exceptions that occur during asynchronous execution */
def reportFailure(cause: Throwable): Unit
/** Prepare for execution (may be optimized away in JavaScript) */
def prepare(): Unit = {}
}
/**
* Factory and utility methods for ExecutionContext instances
*/
object ExecutionContext {
/** Global execution context using JavaScript's default async scheduling */
def global: ExecutionContext
/** Create execution context from Java Executor (limited JavaScript compatibility) */
def fromExecutor(executor: java.util.concurrent.Executor): ExecutionContext
/** Create execution context from Java ExecutorService */
def fromExecutorService(executor: java.util.concurrent.ExecutorService): ExecutionContext
/** Implicit global execution context for convenience */
implicit lazy val global: ExecutionContext
}Usage Examples:
import scala.concurrent.ExecutionContext
import scala.concurrent.Future
// Using global execution context
implicit val ec: ExecutionContext = ExecutionContext.global
// Async computation
val future = Future {
// This runs asynchronously using JavaScript's event loop
Thread.sleep(1000) // Simulated async work
42
}
future.foreach { result =>
println(s"Result: $result")
}
// Custom execution context behavior
val customEc = new ExecutionContext {
def execute(runnable: Runnable): Unit = {
// Custom scheduling logic
js.timers.setTimeout(0) {
try {
runnable.run()
} catch {
case ex: Throwable => reportFailure(ex)
}
}
}
def reportFailure(cause: Throwable): Unit = {
println(s"Async execution failed: ${cause.getMessage}")
cause.printStackTrace()
}
}
// Using custom execution context
val customFuture = Future {
"Hello from custom context"
}(customEc)Asynchronous computation results that integrate with JavaScript's Promise-based ecosystem.
/**
* Represents an asynchronous computation that will complete with a value or exception
* Implemented using JavaScript Promises under the hood
*/
trait Future[+T] {
/** Register callback for successful completion */
def foreach[U](f: T => U)(implicit executor: ExecutionContext): Unit
/** Transform successful result */
def map[S](f: T => S)(implicit executor: ExecutionContext): Future[S]
/** Chain dependent asynchronous operations */
def flatMap[S](f: T => Future[S])(implicit executor: ExecutionContext): Future[S]
/** Handle both success and failure cases */
def transform[S](s: T => S, f: Throwable => Throwable)(implicit executor: ExecutionContext): Future[S]
/** Handle failure cases */
def recover[U >: T](pf: PartialFunction[Throwable, U])(implicit executor: ExecutionContext): Future[U]
/** Handle failure with async operations */
def recoverWith[U >: T](pf: PartialFunction[Throwable, Future[U]])(implicit executor: ExecutionContext): Future[U]
/** Filter successful results */
def filter(p: T => Boolean)(implicit executor: ExecutionContext): Future[T]
/** Complete this future with another future's result */
def zip[U](that: Future[U])(implicit executor: ExecutionContext): Future[(T, U)]
/** Test if future is completed */
def isCompleted: Boolean
/** Get current value if completed (Some(Success/Failure) or None) */
def value: Option[util.Try[T]]
}
/**
* Factory methods and utilities for Future instances
*/
object Future {
/** Create completed successful future */
def successful[T](result: T): Future[T]
/** Create completed failed future */
def failed[T](exception: Throwable): Future[T]
/** Create future from synchronous computation (may throw) */
def apply[T](body: => T)(implicit executor: ExecutionContext): Future[T]
/** Combine multiple futures into future of sequence */
def sequence[A](futures: List[Future[A]])(implicit executor: ExecutionContext): Future[List[A]]
/** Apply function to results of multiple futures */
def traverse[A, B](in: List[A])(fn: A => Future[B])(implicit executor: ExecutionContext): Future[List[B]]
/** Return first completed future */
def firstCompletedOf[T](futures: Iterable[Future[T]])(implicit executor: ExecutionContext): Future[T]
/** Create future that never completes */
def never[T]: Future[T]
/** Convert JavaScript Promise to Scala Future */
def fromPromise[T](promise: js.Promise[T])(implicit executor: ExecutionContext): Future[T]
}Usage Examples:
import scala.concurrent.{Future, ExecutionContext}
import scala.util.{Success, Failure}
implicit val ec: ExecutionContext = ExecutionContext.global
// Basic future creation and transformation
val computation = Future {
// Simulate async computation
val result = (1 to 1000).sum
Thread.sleep(100) // Simulated delay
result
}
val doubled = computation.map(_ * 2)
val stringified = doubled.map(_.toString)
// Chaining dependent operations
val userProfile = for {
userId <- Future.successful(123)
user <- fetchUser(userId)
profile <- fetchProfile(user.profileId)
} yield profile
// Error handling
val robustOperation = Future {
if (scala.util.Random.nextBoolean()) {
throw new RuntimeException("Random failure")
}
"Success!"
}.recover {
case _: RuntimeException => "Recovered from error"
}.recoverWith {
case ex: Exception => Future.successful(s"Handled: ${ex.getMessage}")
}
// Working with multiple futures
val future1 = Future { 10 }
val future2 = Future { 20 }
val future3 = Future { 30 }
val combined = for {
a <- future1
b <- future2
c <- future3
} yield a + b + c
// Sequence operations
val listOfFutures = List(
Future { 1 },
Future { 2 },
Future { 3 }
)
val futureOfList = Future.sequence(listOfFutures)
futureOfList.foreach { list =>
println(s"All results: ${list.mkString(", ")}")
}
// Promise integration (JavaScript interop)
def fetchFromJavaScript(): js.Promise[String] = {
js.Promise.resolve("Data from JavaScript")
}
val scalaFuture = Future.fromPromise(fetchFromJavaScript())
scalaFuture.foreach(println)
// Completion callbacks
computation.onComplete {
case Success(value) => println(s"Computation completed with: $value")
case Failure(exception) => println(s"Computation failed: ${exception.getMessage}")
}Manually completable futures for bridging callback-based APIs with Future-based code.
/**
* A Promise is a writable Future that can be completed exactly once
* Useful for converting callback-based APIs to Future-based APIs
*/
trait Promise[T] {
/** The future associated with this promise */
def future: Future[T]
/** Complete the promise with a successful value */
def success(value: T): this.type
/** Complete the promise with a failure */
def failure(exception: Throwable): this.type
/** Complete the promise with a Try result */
def complete(result: util.Try[T]): this.type
/** Try to complete with successful value (returns true if successful) */
def trySuccess(value: T): Boolean
/** Try to complete with failure (returns true if successful) */
def tryFailure(exception: Throwable): Boolean
/** Try to complete with Try result (returns true if successful) */
def tryComplete(result: util.Try[T]): Boolean
/** Test if promise is completed */
def isCompleted: Boolean
}
/**
* Factory methods for Promise instances
*/
object Promise {
/** Create a new empty promise */
def apply[T](): Promise[T]
/** Create promise completed with successful value */
def successful[T](result: T): Promise[T]
/** Create promise completed with failure */
def failed[T](exception: Throwable): Promise[T]
}Usage Examples:
import scala.concurrent.{Promise, Future, ExecutionContext}
import scala.util.{Success, Failure}
implicit val ec: ExecutionContext = ExecutionContext.global
// Converting callback API to Future
def callbackBasedAPI(callback: (String, Option[Throwable]) => Unit): Unit = {
// Simulate async callback API
js.timers.setTimeout(1000) {
if (scala.util.Random.nextBoolean()) {
callback("Success result", None)
} else {
callback(null, Some(new RuntimeException("API Error")))
}
}
}
def futureBasedAPI(): Future[String] = {
val promise = Promise[String]()
callbackBasedAPI { (result, error) =>
error match {
case Some(ex) => promise.failure(ex)
case None => promise.success(result)
}
}
promise.future
}
// Using the converted API
val result = futureBasedAPI()
result.foreach(println)
// Manual promise completion
val manualPromise = Promise[Int]()
val manualFuture = manualPromise.future
// Complete from another thread/async context
js.timers.setTimeout(2000) {
manualPromise.success(42)
}
manualFuture.foreach { value =>
println(s"Manual promise completed with: $value")
}
// Promise with Try completion
val tryPromise = Promise[String]()
val computation = util.Try {
if (scala.util.Random.nextBoolean()) {
"Computation succeeded"
} else {
throw new RuntimeException("Computation failed")
}
}
tryPromise.complete(computation)
tryPromise.future.foreach(println)
// Safe completion attempts
val safePromise = Promise[String]()
val completed1 = safePromise.trySuccess("First attempt") // true
val completed2 = safePromise.trySuccess("Second attempt") // false
println(s"First completion: $completed1")
println(s"Second completion: $completed2")Install with Tessl CLI
npx tessl i tessl/maven-org-scala-js--scalajs-scalalib-2-13