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