0
# Concurrent Programming
1
2
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.
3
4
## Capabilities
5
6
### Execution Context
7
8
Core abstraction for executing asynchronous operations, adapted for JavaScript's single-threaded event loop model.
9
10
```scala { .api }
11
/**
12
* Represents a context where asynchronous operations can be executed
13
* In JavaScript, this typically uses setTimeout, Promise.resolve, or similar mechanisms
14
*/
15
trait ExecutionContext {
16
/** Execute the given runnable asynchronously */
17
def execute(runnable: Runnable): Unit
18
19
/** Report uncaught exceptions that occur during asynchronous execution */
20
def reportFailure(cause: Throwable): Unit
21
22
/** Prepare for execution (may be optimized away in JavaScript) */
23
def prepare(): Unit = {}
24
}
25
26
/**
27
* Factory and utility methods for ExecutionContext instances
28
*/
29
object ExecutionContext {
30
/** Global execution context using JavaScript's default async scheduling */
31
def global: ExecutionContext
32
33
/** Create execution context from Java Executor (limited JavaScript compatibility) */
34
def fromExecutor(executor: java.util.concurrent.Executor): ExecutionContext
35
36
/** Create execution context from Java ExecutorService */
37
def fromExecutorService(executor: java.util.concurrent.ExecutorService): ExecutionContext
38
39
/** Implicit global execution context for convenience */
40
implicit lazy val global: ExecutionContext
41
}
42
```
43
44
**Usage Examples:**
45
46
```scala
47
import scala.concurrent.ExecutionContext
48
import scala.concurrent.Future
49
50
// Using global execution context
51
implicit val ec: ExecutionContext = ExecutionContext.global
52
53
// Async computation
54
val future = Future {
55
// This runs asynchronously using JavaScript's event loop
56
Thread.sleep(1000) // Simulated async work
57
42
58
}
59
60
future.foreach { result =>
61
println(s"Result: $result")
62
}
63
64
// Custom execution context behavior
65
val customEc = new ExecutionContext {
66
def execute(runnable: Runnable): Unit = {
67
// Custom scheduling logic
68
js.timers.setTimeout(0) {
69
try {
70
runnable.run()
71
} catch {
72
case ex: Throwable => reportFailure(ex)
73
}
74
}
75
}
76
77
def reportFailure(cause: Throwable): Unit = {
78
println(s"Async execution failed: ${cause.getMessage}")
79
cause.printStackTrace()
80
}
81
}
82
83
// Using custom execution context
84
val customFuture = Future {
85
"Hello from custom context"
86
}(customEc)
87
```
88
89
### Future Operations
90
91
Asynchronous computation results that integrate with JavaScript's Promise-based ecosystem.
92
93
```scala { .api }
94
/**
95
* Represents an asynchronous computation that will complete with a value or exception
96
* Implemented using JavaScript Promises under the hood
97
*/
98
trait Future[+T] {
99
/** Register callback for successful completion */
100
def foreach[U](f: T => U)(implicit executor: ExecutionContext): Unit
101
102
/** Transform successful result */
103
def map[S](f: T => S)(implicit executor: ExecutionContext): Future[S]
104
105
/** Chain dependent asynchronous operations */
106
def flatMap[S](f: T => Future[S])(implicit executor: ExecutionContext): Future[S]
107
108
/** Handle both success and failure cases */
109
def transform[S](s: T => S, f: Throwable => Throwable)(implicit executor: ExecutionContext): Future[S]
110
111
/** Handle failure cases */
112
def recover[U >: T](pf: PartialFunction[Throwable, U])(implicit executor: ExecutionContext): Future[U]
113
114
/** Handle failure with async operations */
115
def recoverWith[U >: T](pf: PartialFunction[Throwable, Future[U]])(implicit executor: ExecutionContext): Future[U]
116
117
/** Filter successful results */
118
def filter(p: T => Boolean)(implicit executor: ExecutionContext): Future[T]
119
120
/** Complete this future with another future's result */
121
def zip[U](that: Future[U])(implicit executor: ExecutionContext): Future[(T, U)]
122
123
/** Test if future is completed */
124
def isCompleted: Boolean
125
126
/** Get current value if completed (Some(Success/Failure) or None) */
127
def value: Option[util.Try[T]]
128
}
129
130
/**
131
* Factory methods and utilities for Future instances
132
*/
133
object Future {
134
/** Create completed successful future */
135
def successful[T](result: T): Future[T]
136
137
/** Create completed failed future */
138
def failed[T](exception: Throwable): Future[T]
139
140
/** Create future from synchronous computation (may throw) */
141
def apply[T](body: => T)(implicit executor: ExecutionContext): Future[T]
142
143
/** Combine multiple futures into future of sequence */
144
def sequence[A](futures: List[Future[A]])(implicit executor: ExecutionContext): Future[List[A]]
145
146
/** Apply function to results of multiple futures */
147
def traverse[A, B](in: List[A])(fn: A => Future[B])(implicit executor: ExecutionContext): Future[List[B]]
148
149
/** Return first completed future */
150
def firstCompletedOf[T](futures: Iterable[Future[T]])(implicit executor: ExecutionContext): Future[T]
151
152
/** Create future that never completes */
153
def never[T]: Future[T]
154
155
/** Convert JavaScript Promise to Scala Future */
156
def fromPromise[T](promise: js.Promise[T])(implicit executor: ExecutionContext): Future[T]
157
}
158
```
159
160
**Usage Examples:**
161
162
```scala
163
import scala.concurrent.{Future, ExecutionContext}
164
import scala.util.{Success, Failure}
165
166
implicit val ec: ExecutionContext = ExecutionContext.global
167
168
// Basic future creation and transformation
169
val computation = Future {
170
// Simulate async computation
171
val result = (1 to 1000).sum
172
Thread.sleep(100) // Simulated delay
173
result
174
}
175
176
val doubled = computation.map(_ * 2)
177
val stringified = doubled.map(_.toString)
178
179
// Chaining dependent operations
180
val userProfile = for {
181
userId <- Future.successful(123)
182
user <- fetchUser(userId)
183
profile <- fetchProfile(user.profileId)
184
} yield profile
185
186
// Error handling
187
val robustOperation = Future {
188
if (scala.util.Random.nextBoolean()) {
189
throw new RuntimeException("Random failure")
190
}
191
"Success!"
192
}.recover {
193
case _: RuntimeException => "Recovered from error"
194
}.recoverWith {
195
case ex: Exception => Future.successful(s"Handled: ${ex.getMessage}")
196
}
197
198
// Working with multiple futures
199
val future1 = Future { 10 }
200
val future2 = Future { 20 }
201
val future3 = Future { 30 }
202
203
val combined = for {
204
a <- future1
205
b <- future2
206
c <- future3
207
} yield a + b + c
208
209
// Sequence operations
210
val listOfFutures = List(
211
Future { 1 },
212
Future { 2 },
213
Future { 3 }
214
)
215
216
val futureOfList = Future.sequence(listOfFutures)
217
futureOfList.foreach { list =>
218
println(s"All results: ${list.mkString(", ")}")
219
}
220
221
// Promise integration (JavaScript interop)
222
def fetchFromJavaScript(): js.Promise[String] = {
223
js.Promise.resolve("Data from JavaScript")
224
}
225
226
val scalaFuture = Future.fromPromise(fetchFromJavaScript())
227
scalaFuture.foreach(println)
228
229
// Completion callbacks
230
computation.onComplete {
231
case Success(value) => println(s"Computation completed with: $value")
232
case Failure(exception) => println(s"Computation failed: ${exception.getMessage}")
233
}
234
```
235
236
### Promise
237
238
Manually completable futures for bridging callback-based APIs with Future-based code.
239
240
```scala { .api }
241
/**
242
* A Promise is a writable Future that can be completed exactly once
243
* Useful for converting callback-based APIs to Future-based APIs
244
*/
245
trait Promise[T] {
246
/** The future associated with this promise */
247
def future: Future[T]
248
249
/** Complete the promise with a successful value */
250
def success(value: T): this.type
251
252
/** Complete the promise with a failure */
253
def failure(exception: Throwable): this.type
254
255
/** Complete the promise with a Try result */
256
def complete(result: util.Try[T]): this.type
257
258
/** Try to complete with successful value (returns true if successful) */
259
def trySuccess(value: T): Boolean
260
261
/** Try to complete with failure (returns true if successful) */
262
def tryFailure(exception: Throwable): Boolean
263
264
/** Try to complete with Try result (returns true if successful) */
265
def tryComplete(result: util.Try[T]): Boolean
266
267
/** Test if promise is completed */
268
def isCompleted: Boolean
269
}
270
271
/**
272
* Factory methods for Promise instances
273
*/
274
object Promise {
275
/** Create a new empty promise */
276
def apply[T](): Promise[T]
277
278
/** Create promise completed with successful value */
279
def successful[T](result: T): Promise[T]
280
281
/** Create promise completed with failure */
282
def failed[T](exception: Throwable): Promise[T]
283
}
284
```
285
286
**Usage Examples:**
287
288
```scala
289
import scala.concurrent.{Promise, Future, ExecutionContext}
290
import scala.util.{Success, Failure}
291
292
implicit val ec: ExecutionContext = ExecutionContext.global
293
294
// Converting callback API to Future
295
def callbackBasedAPI(callback: (String, Option[Throwable]) => Unit): Unit = {
296
// Simulate async callback API
297
js.timers.setTimeout(1000) {
298
if (scala.util.Random.nextBoolean()) {
299
callback("Success result", None)
300
} else {
301
callback(null, Some(new RuntimeException("API Error")))
302
}
303
}
304
}
305
306
def futureBasedAPI(): Future[String] = {
307
val promise = Promise[String]()
308
309
callbackBasedAPI { (result, error) =>
310
error match {
311
case Some(ex) => promise.failure(ex)
312
case None => promise.success(result)
313
}
314
}
315
316
promise.future
317
}
318
319
// Using the converted API
320
val result = futureBasedAPI()
321
result.foreach(println)
322
323
// Manual promise completion
324
val manualPromise = Promise[Int]()
325
val manualFuture = manualPromise.future
326
327
// Complete from another thread/async context
328
js.timers.setTimeout(2000) {
329
manualPromise.success(42)
330
}
331
332
manualFuture.foreach { value =>
333
println(s"Manual promise completed with: $value")
334
}
335
336
// Promise with Try completion
337
val tryPromise = Promise[String]()
338
339
val computation = util.Try {
340
if (scala.util.Random.nextBoolean()) {
341
"Computation succeeded"
342
} else {
343
throw new RuntimeException("Computation failed")
344
}
345
}
346
347
tryPromise.complete(computation)
348
tryPromise.future.foreach(println)
349
350
// Safe completion attempts
351
val safePromise = Promise[String]()
352
353
val completed1 = safePromise.trySuccess("First attempt") // true
354
val completed2 = safePromise.trySuccess("Second attempt") // false
355
356
println(s"First completion: $completed1")
357
println(s"Second completion: $completed2")
358
```