/* * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. */ package kotlinx.coroutines import kotlin.coroutines.* import kotlin.js.* /** * Starts new coroutine and returns its result as an implementation of [Promise]. * * Coroutine context is inherited from a [CoroutineScope], additional context elements can be specified with [context] argument. * If the context does not have any dispatcher nor any other [ContinuationInterceptor], then [Dispatchers.Default] is used. * The parent job is inherited from a [CoroutineScope] as well, but it can also be overridden * with corresponding [context] element. * * By default, the coroutine is immediately scheduled for execution. * Other options can be specified via `start` parameter. See [CoroutineStart] for details. * * @param context additional to [CoroutineScope.coroutineContext] context of the coroutine. * @param start coroutine start option. The default value is [CoroutineStart.DEFAULT]. * @param block the coroutine code. */ public fun CoroutineScope.promise( context: CoroutineContext = EmptyCoroutineContext, start: CoroutineStart = CoroutineStart.DEFAULT, block: suspend CoroutineScope.() -> T ): Promise = async(context, start, block).asPromise() /** * Converts this deferred value to the instance of [Promise]. */ public fun Deferred.asPromise(): Promise { val promise = Promise { resolve, reject -> invokeOnCompletion { val e = getCompletionExceptionOrNull() if (e != null) { reject(e) } else { resolve(getCompleted()) } } } promise.asDynamic().deferred = this return promise } /** * Converts this promise value to the instance of [Deferred]. */ public fun Promise.asDeferred(): Deferred { val deferred = asDynamic().deferred @Suppress("UnsafeCastFromDynamic") return deferred ?: GlobalScope.async(start = CoroutineStart.UNDISPATCHED) { await() } } /** * Awaits for completion of the promise without blocking. * * This suspending function is cancellable. * If the [Job] of the current coroutine is cancelled or completed while this suspending function is waiting, this function * stops waiting for the promise and immediately resumes with [CancellationException]. * There is a **prompt cancellation guarantee**. If the job was cancelled while this function was * suspended, it will not resume successfully. See [suspendCancellableCoroutine] documentation for low-level details. */ public suspend fun Promise.await(): T = suspendCancellableCoroutine { cont: CancellableContinuation -> this@await.then( onFulfilled = { cont.resume(it) }, onRejected = { cont.resumeWithException(it) }) }