1 /*
<lambda>null2 * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3 */
4
5 package kotlinx.coroutines
6
7 import kotlin.coroutines.*
8 import kotlin.js.*
9
10 /**
11 * Starts new coroutine and returns its result as an implementation of [Promise].
12 *
13 * Coroutine context is inherited from a [CoroutineScope], additional context elements can be specified with [context] argument.
14 * If the context does not have any dispatcher nor any other [ContinuationInterceptor], then [Dispatchers.Default] is used.
15 * The parent job is inherited from a [CoroutineScope] as well, but it can also be overridden
16 * with corresponding [context] element.
17 *
18 * By default, the coroutine is immediately scheduled for execution.
19 * Other options can be specified via `start` parameter. See [CoroutineStart] for details.
20 *
21 * @param context additional to [CoroutineScope.coroutineContext] context of the coroutine.
22 * @param start coroutine start option. The default value is [CoroutineStart.DEFAULT].
23 * @param block the coroutine code.
24 */
25 public fun <T> CoroutineScope.promise(
26 context: CoroutineContext = EmptyCoroutineContext,
27 start: CoroutineStart = CoroutineStart.DEFAULT,
28 block: suspend CoroutineScope.() -> T
29 ): Promise<T> =
30 async(context, start, block).asPromise()
31
32 /**
33 * Converts this deferred value to the instance of [Promise].
34 */
35 public fun <T> Deferred<T>.asPromise(): Promise<T> {
36 val promise = Promise<T> { resolve, reject ->
37 invokeOnCompletion {
38 val e = getCompletionExceptionOrNull()
39 if (e != null) {
40 reject(e)
41 } else {
42 resolve(getCompleted())
43 }
44 }
45 }
46 promise.asDynamic().deferred = this
47 return promise
48 }
49
50 /**
51 * Converts this promise value to the instance of [Deferred].
52 */
asDeferrednull53 public fun <T> Promise<T>.asDeferred(): Deferred<T> {
54 val deferred = asDynamic().deferred
55 @Suppress("UnsafeCastFromDynamic")
56 return deferred ?: GlobalScope.async(start = CoroutineStart.UNDISPATCHED) { await() }
57 }
58
59 /**
60 * Awaits for completion of the promise without blocking.
61 *
62 * This suspending function is cancellable.
63 * If the [Job] of the current coroutine is cancelled or completed while this suspending function is waiting, this function
64 * stops waiting for the promise and immediately resumes with [CancellationException].
65 * There is a **prompt cancellation guarantee**. If the job was cancelled while this function was
66 * suspended, it will not resume successfully. See [suspendCancellableCoroutine] documentation for low-level details.
67 */
awaitnull68 public suspend fun <T> Promise<T>.await(): T = suspendCancellableCoroutine { cont: CancellableContinuation<T> ->
69 this@await.then(
70 onFulfilled = { cont.resume(it) },
71 onRejected = { cont.resumeWithException(it) })
72 }
73