Skip to content

Commit b705e1c

Browse files
committed
Document the async function
1 parent 4ad4272 commit b705e1c

File tree

1 file changed

+83
-20
lines changed

1 file changed

+83
-20
lines changed

kotlinx-coroutines-core/common/src/Builders.common.kt

Lines changed: 83 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ import kotlin.jvm.*
3434
*
3535
* ## Structured Concurrency
3636
*
37+
* ### Coroutine context
38+
*
3739
* [launch] creates a *child coroutine* of `this` [CoroutineScope].
3840
*
3941
* The context of the new coroutine is created like this:
@@ -55,8 +57,10 @@ import kotlin.jvm.*
5557
* If the [block] throws a [CancellationException], the coroutine is considered cancelled,
5658
* and if it throws any other exception, the coroutine is considered failed.
5759
*
60+
* ### Interactions between coroutines
61+
*
5862
* The details of structured concurrency are described in the [CoroutineScope] interface documentation.
59-
* Here is a restatement of some main points as they relate to `launch`:
63+
* Here is a restatement of some main points as they relate to [launch]:
6064
*
6165
* - The lifecycle of the parent [CoroutineScope] can not end until this coroutine
6266
* (as well as all its children) completes.
@@ -113,6 +117,16 @@ import kotlin.jvm.*
113117
* there is no reliable way to learn about that exception in general.
114118
* [async] is a better choice if the result of the coroutine needs to be accessed from another coroutine.
115119
*
120+
* ## Differences from [async]
121+
*
122+
* [launch] is similar to [async] whose block returns a [Unit] value.
123+
*
124+
* The only difference is the handling of uncaught coroutine exceptions:
125+
* if an [async] coroutine fails with an exception, then even if the exception can not be propagated to the parent,
126+
* a [CoroutineExceptionHandler] will not be invoked.
127+
* Instead, the user of [async] must call [Deferred.await] to get the result of the coroutine,
128+
* which will be the uncaught exception.
129+
*
116130
* ## Pitfalls
117131
*
118132
* ### [CancellationException] silently stopping computations
@@ -182,7 +196,7 @@ import kotlin.jvm.*
182196
*
183197
* @param context additional to [CoroutineScope.coroutineContext] context of the coroutine.
184198
* @param start coroutine start option. The default value is [CoroutineStart.DEFAULT].
185-
* @param block the coroutine code which will be invoked in the context of the provided scope.
199+
* @param block the coroutine code which will be invoked in the child coroutine.
186200
**/
187201
public fun CoroutineScope.launch(
188202
context: CoroutineContext = EmptyCoroutineContext,
@@ -200,24 +214,73 @@ public fun CoroutineScope.launch(
200214
// --------------- async ---------------
201215

202216
/**
203-
* Creates a coroutine and returns its future result as an implementation of [Deferred].
204-
* The running coroutine is cancelled when the resulting deferred is [cancelled][Job.cancel].
205-
* The resulting coroutine has a key difference compared with similar primitives in other languages
206-
* and frameworks: it cancels the parent job (or outer scope) on failure to enforce *structured concurrency* paradigm.
207-
* To change that behaviour, supervising parent ([SupervisorJob] or [supervisorScope]) can be used.
208-
*
209-
* Coroutine context is inherited from a [CoroutineScope], additional context elements can be specified with [context] argument.
210-
* If the context does not have any dispatcher nor any other [ContinuationInterceptor], then [Dispatchers.Default] is used.
211-
* The parent job is inherited from a [CoroutineScope] as well, but it can also be overridden
212-
* with corresponding [context] element.
213-
*
214-
* By default, the coroutine is immediately scheduled for execution.
215-
* Other options can be specified via `start` parameter. See [CoroutineStart] for details.
216-
* An optional [start] parameter can be set to [CoroutineStart.LAZY] to start coroutine _lazily_. In this case,
217-
* the resulting [Deferred] is created in _new_ state. It can be explicitly started with [start][Job.start]
218-
* function and will be started implicitly on the first invocation of [join][Job.join], [await][Deferred.await] or [awaitAll].
219-
*
220-
* @param block the coroutine code.
217+
* Launches a new *child coroutine* of [CoroutineScope] without blocking the current thread
218+
* and returns a reference to the coroutine as a [Deferred] that can be used to access the final value.
219+
*
220+
* [block] is the computation of the new coroutine that will run concurrently.
221+
* The coroutine is considered active until the block and all the child coroutines created in it finish.
222+
* The result of executing the [block] is available via the returned [Deferred].
223+
*
224+
* [context] specifies the additional context elements for the coroutine to combine with
225+
* the elements already present in the [CoroutineScope.coroutineContext].
226+
* It is incorrect to pass a [Job] element there, as this breaks structured concurrency.
227+
*
228+
* By default, the coroutine is scheduled for execution on its [ContinuationInterceptor].
229+
* There is no guarantee that it will start immediately: this is decided by the [ContinuationInterceptor].
230+
* It is possible that the new coroutine will be cancelled before starting, in which case its code will not be executed.
231+
* The [start] parameter can be used to adjust this behavior. See [CoroutineStart] for details.
232+
*
233+
* ## Structured Concurrency
234+
*
235+
* ### Coroutine context
236+
*
237+
* [async] creates a *child coroutine* of `this` [CoroutineScope].
238+
*
239+
* See the corresponding subsection in the [launch] documentation for details on how the coroutine context is created.
240+
* In essence, the elements of [context] are combined with the elements of the [CoroutineScope.coroutineContext],
241+
* typically overriding them. It is incorrect to pass a [Job] element there, as this breaks structured concurrency.
242+
*
243+
* ### Interactions between coroutines
244+
*
245+
* The details of structured concurrency are described in the [CoroutineScope] interface documentation.
246+
* Here is a restatement of some main points as they relate to [async]:
247+
*
248+
* - The lifecycle of the parent [CoroutineScope] can not end until this coroutine
249+
* (as well as all its children) completes.
250+
* - If the parent [CoroutineScope] is cancelled, this coroutine is cancelled as well.
251+
* - If this coroutine fails with a non-[CancellationException] exception
252+
* and the parent [CoroutineScope] has a non-supervisor [Job] in its context,
253+
* the parent [Job] is cancelled with this exception.
254+
* - If this coroutine fails with an exception and the parent [CoroutineScope] has a supervisor [Job] or no job at all
255+
* (as is the case with [GlobalScope] or malformed scopes),
256+
* the exception is considered uncaught and is only available through the returned [Deferred].
257+
* - The lifecycle of the [CoroutineScope] passed as the receiver to the [block]
258+
* will not end until the [block] completes (or gets cancelled before ever having a chance to run).
259+
* - If the [block] throws a [CancellationException], the coroutine is considered cancelled,
260+
* cancelling all its children in turn, but the parent does not get notified.
261+
*
262+
* ## Communicating with the coroutine
263+
*
264+
* [Deferred.await] can be used to suspend the current coroutine until the result of the [async] coroutine is available.
265+
* It returns the result of the [block] executed in the [async] coroutine.
266+
* Note that if the [async] coroutine fails with an exception, [Deferred.await] will also throw that exception,
267+
* including [CancellationException] if the coroutine was cancelled.
268+
* See the "CancellationException silently stopping computations" pitfall in the [launch] documentation.
269+
*
270+
* [Deferred.cancel] can be used to cancel the coroutine, and [Deferred.join] can be used to block until its completion
271+
* without blocking the current thread or accessing its result.
272+
* Note that [Deferred.join] succeeds even if the coroutine was cancelled or failed with an exception.
273+
* [Deferred.cancelAndJoin] is a convenience function that combines cancellation and joining.
274+
*
275+
* If the coroutine was started with [start] set to [CoroutineStart.LAZY], the coroutine will not be scheduled
276+
* to run on its [ContinuationInterceptor] immediately.
277+
* [Deferred.start] can be used to start the coroutine explicitly,
278+
* and awaiting its result using [Deferred.await] or [awaitAll] or its completion using [Deferred.join]
279+
* also causes the coroutine to start executing.
280+
*
281+
* @param context additional to [CoroutineScope.coroutineContext] context of the coroutine.
282+
* @param start coroutine start option. The default value is [CoroutineStart.DEFAULT].
283+
* @param block the coroutine code which will be invoked in the child coroutine.
221284
*/
222285
public fun <T> CoroutineScope.async(
223286
context: CoroutineContext = EmptyCoroutineContext,

0 commit comments

Comments
 (0)