From 7cf33038036c9676992af77a96cdcbe38d95850f Mon Sep 17 00:00:00 2001 From: Jon Tippens Date: Mon, 3 Jun 2019 19:40:47 -0700 Subject: [PATCH 01/47] Add WIP async await codelab --- src/_guides/language/async-await.md | 344 ++++++++++++++++++++++++++++ 1 file changed, 344 insertions(+) create mode 100644 src/_guides/language/async-await.md diff --git a/src/_guides/language/async-await.md b/src/_guides/language/async-await.md new file mode 100644 index 0000000000..ff3a0b63e4 --- /dev/null +++ b/src/_guides/language/async-await.md @@ -0,0 +1,344 @@ +--- + +--- + +# + + + + +## Asynchronous Dart Code: Future, async, and await + + + + +## Introduction + + + +Welcome to the asynchronous Dart codelab! In this codelab you'll practice using Dart to run asynchronous code via the `async` and `await` keywords. + +In addition to explanations, this codelab includes embedded editors that show you working code examples and coding exercises. You can use these editors to test your knowledge by completing the exercises. + +Before you begin this codelab, you should: + +* Have some experience writing asynchronous code -- for example, writing code that sends a request to a server and then handles a response + +When you finish this codelab, you'll know the following: + +* How to use the `async` keyword +* How to use the `await` keyword +* When to use `async` and `await` in your code +* How your code will be executed when you use the `async/await` keywords +* How to handle errors from an asynchronous call using `try/catch` expressions in async functions. +* Where to find more information for related to the `async/await` material covered in this codelab. + + +## Why Async Matters + + + + +Asynchronous operations let your program complete other work while waiting for an operation to finish. Some common processes that require asynchronous operations include: + +* Fetching data over a network +* Writing to a database +* Reading data from a file + +In order to write code that implements these features, you will need to learn the Dart syntax for Futures, async, and await. In Dart you cannot use synchronous code to handle asynchronous operations. + +Consider the following example that fails to print the desired user order to the console: + +Note: this example shows how *not* to handle asynchronous code in dart. {:.fails-sa} + +``` +String createOrderMessage () { + var order = getUserOrder(); + return 'Your order is: $order'; +} + +Future getUserOrder() { + // Imagine that this function is more complex and slow + return Future.delayed(Duration(seconds: 4), () => 'Large Latte'); +} + +main() { + print(createOrderMessage()); +} +``` + +`// Your order is: Instance of '_Future'` + +In the above code: + +* `getUserOrder` is an asynchronous function that waits four seconds before returning a string describing the user's order: a large latte. (For a further explanation you can [find out more about Future.delayed](https://api.dartlang.org/stable/2.3.0/dart-async/Future/Future.delayed.html)) +* `createOrderMessage` calls `getUserOrder` as if it were a synchronous function -- it invokes `getUserOrder` and immediately prints the result. +* Since `getUserOrder` waits four seconds before returning the user's order, `createOrderMessage` never actually prints the user's order. Instead you can see `Instance of '_Future'` printed to the console as the value returned by `createOrderMessage().` + +What is a future, and how do we write code to handle the asynchronous function `getUserOrder`? + + +## Async in Dart: What is a Future? + + + +In Dart, the result of an asynchronous operation is represented by a [Future](https://api.dartlang.org/stable/2.2.0/dart-async/Future-class.html) object. A future object can be in one of two states: uncompleted or completed. + +### **Lifecycle of a Future Object** + +### **Uncompleted** + +When you invoke a function that returns a future, that function immediately returns a future object in an uncompleted state. While in its uncompleted state, a future object is simply waiting for asynchronous operations to finish or to throw an error. + +### **Completed ** + +There are two ways that a future object can complete: + +#### **Completed - Success** + +If the asynchronous operations succeed, the future completes and returns a result of type T. For example, [Future](https://api.dartlang.org/stable/2.3.0/dart-async/Future-class.html)`` is the type signature for a future object that produces a string result. If a future produces a result that isn't a usable value, then the future's type is `Future`. + +#### **Completed - Error** + +Instead of succeeding, if the asynchronous operations being performed by the function throw an error, the future completes and returns an error. + +To see this lifecycle at work consider what happens after you invoke the `getUserOrder` function: + +``` +String createOrderMessage () { + var order = getUserOrder(); + return 'Your order is: $order'; +} + +Future getUserOrder() { + // Imagine that this function is more complex and slow + return Future.delayed(Duration(seconds: 4), () => 'Large Latte'); +} + +main() { + print(createOrderMessage()); +} +``` + +`// Your order is: Instance of '_Future'` + +* after 1 second has passed: the future is uncomplete - we cannot access the desired result yet + +` Your order is: Instance of '_Future'` + +* after 4 seconds have passed: the future completes, returning the desired result + +`'Large Latte'` + + +But how do you access this result that completes 4 seconds later? In addition to providing future objects, Dart also provides a clean and easy way to handle their results -- the `async` and `await` keywords. + +Quick Review: + +* In Dart, the result of an asynchronous operation is represented by a [Future](https://api.dartlang.org/stable/2.2.0/dart-async/Future-class.html)`` object that produces a result of type `T`. For example, [Future](https://api.dartlang.org/stable/2.3.0/dart-async/Future-class.html)`` is the type signature for a future object that produces a string result. If a future produces a result that isn't a usable value, then the future's type is `Future`. +* A future can be in one of two states: uncompleted, or completed. +* A completed future can either (1) complete with a result or (2) complete with an error +* When a function that returns a future is invoked, two things happen: + +1. The function queues up work to be done and returns an uncompleted future. +2. Later, when the operation is finished, the future completes with a value or with an error. + + +## Working with Futures in Dart: async and await + + + +In the previous section you learned that, in Dart, future objects represent the results of asynchronous operations -- if a function does asynchronous work, it returns a future object. But how do we access the results of future objects when using asynchronous functions? + +The `async` and `await` keywords provide a declarative way to (1) define asynchronous functions and (2) access their results *after they have completed.* + + +To define an `async` function: + +1. Add the `async` keyword after the function's parameters but before the function's body. + + createOrderMessage () async { + +2. Update the function's type signature to return a future. In the following example, we define an `async` function that completes with a string. + + Future createOrderMessage () async { + + *Note: You can * [use Future](https://dart.dev/guides/language/effective-dart/design#do-use-futurevoid-as-the-return-type-of-asynchronous-members-that-do-not-produce-values) * as the return type for asynchronous functions that don't return usable values. * + + +Once you have defined an async function, that function will return a future object. Using the await keyword, you can "wait" for the completed future to return either its value or its error. + + String order = await getUserOrder(); + +Remember, you can only use the `await` keyword within an `async` function body. The following example demonstrates how to convert `createOrderMessage` from synchronous to asynchronous: + +``` +// BEFORE: handle a function that returns a string + +String createOrderMessage () { + var order = getUserOrder(); + return 'Your order is: $order'; +} + +main() { + print(createOrderMessage()); +} +``` + +``` +// After: handle an async function that returns a Future + +Future createOrderMessage () async { + var order = await getUserOrder(); + return 'Your order is: $order'; +} + +main() async { + print(await createOrderMessage()); +} +``` + +* *Note: * [All functions return a value](https://dart.dev/guides/language/language-tour#return-values) * even if you don't explicitly use the * *`return`* * keyword. * +* *Note: Dart can * [infer the Future type](https://dart.dev/guides/language/sound-dart#type-inference) * for you. +* + +This code has only three changes from the preceding implementation: + +1. Mark the return type for `createOrderMessage` with `Future` +2. Add **`async`** before the method body (the `createOrderMessage` and the `main` method) +3. Add **`await`** before the calling the asynchronous function (before we invoke `getUserOrder` and `createOrderMessage`) + + +## Execution Flow with async and await + + + +As of Dart 2.0, functions marked as `async` run synchronously until the first `await` keyword. This means that within an `async` function's body, all synchronous code is immediately executed. This is demonstrated in the following example: + +``` +void createOrderMessage () async { + print('Awaiting user order...'); + var order = await getUserOrder(); + print('Your order is: $order'); +} + +Future getUserOrder() { + return Future.delayed(Duration(seconds: 4), () => 'Large Latte'); +} + +main() async { + await createOrderMessage(); +} + +// Output: +// Awaiting user order... +// (4 second pause) +// Your order is: Large Latte +``` + +Notice that the timing of the output shifts if we move the print statement "Awaiting user order" to the line after the first await keyword in `createOrderMessage`: + +``` +void createOrderMessage () async { + var order = await getUserOrder(); + print('Awaiting user order...'); + print('Your order is: $order'); +} + +Future getUserOrder() { + return Future.delayed(Duration(seconds: 4), () => 'Large Latte'); +} + +main() async { + await createOrderMessage(); +} + +// Output: +// (4 seconds pause) +// Awaiting user order... +// Your order is: Large Latte +``` + + +## Practice Using async and await + + + +The exercise below is created with partially completed code snippets as a failing unit test, and you will be writing code and make it pass. Verify your code by clicking the Run button. + +Add the following: + +* Part 1: Add logic to the `reportUserRole` function so that it returns a Future that produces the String result ‘User role: !'. The can be obtained by calling the provided async function `getRole` which returns a `String` describing the user role. Example return value from `reportUserRole()`: `'User role: tester'` +* Part 2: Write an `async` function `reportLogins` that returns the string: ‘Total number of logins: '. The can be obtained by calling the provided asynchronous function `getLoginAmount`, which returns an `int` representing the number of times that the user has logged in. Example return value from `reportLogins(): 'Total number of logins: 57'` + + +## Handling errors + + + +`Async` functions can handle errors using try-catch: + +``` +void createOrderMessage () async { + try { + var order = await getUserOrder(); + print('Awaiting user order...'); + } catch (err) { + print('Caught error: $err'); + } +} + +Future getUserOrder() { + // Imagine that this function is more complex and throws an exception + var str = Future.delayed(Duration(seconds: 4), () => throw 'Cannot locate user order'); + return str; +} + +main() async { + await createOrderMessage(); +} + +// Caught error: Cannot locate user order +``` + +The try-catch code behaves in the same way with asynchronous code as it does with synchronous code: if the code within the `try` block throws an exception, the code inside the `catch` clause executes. + + +## Practice Handling Errors with async and awaitImplement code to accomplish the following: + + + +* Make `changeUsername` call the provided asynchronous function `getNewUsername`, and return its result +* `changeUsername` must catch and return any errors thrown by getNewUsername, prefixing the returned error with the following string: `Error:` +* Example return value from `changeUsername` when `getNewUsername` throws an error: `Error: Username must contain only alphanumeric values` + + +## Putting It All Together + + + +Now it's time to sum up what you've learned in one final exercise. In the following snippet, write the following: + +* Part1: Write a function `addHello.` `addHello` should take a single string argument, and return that argument surrounded by the text ‘Hello !' +* Part2: Write a function `greetUser` that takes no arguments +* To obtain the username, `greetUser` should call the provided async function `getUsername`, which waits for 1 second before returning a string +* `greetUser` should create a greeting for the user by calling `addHello,` passing it the username, and returning the result. For example, if the username is ‘Jenny' `greetUser` should create and return the greeting "Hello Jenny!" +* Part3: Write a function `sayGoodbye` that takes no arguments +* Within its function body, `sayGoodbye` should call the provided async function `logoutUser` which takes no arguments. +* `sayGoodbye` should catch any errors thrown by `logoutUser` +* If `logoutUser` succeeds, `sayGoodbye` should return the string " Thanks! See you next time!" where is the String value returned by calling `logoutUser` + + + +Find Out More + +* [Futures](https://www.dartlang.org/tutorials/language/futures) +* [The Event Loop in Dart](https://webdev.dartlang.org/articles/performance/event-loop) +* [Isolates](https://api.dartlang.org/stable/2.2.0/dart-isolate/dart-isolate-library.html) +* Read about [Dart's type system](https://dart.dev/guides/language/sound-dart) for more examples of type signatures with futures. You should [prefer signatures in function type annotations](https://dart.dev/guides/language/effective-dart/design#prefer-signatures-in-function-type-annotations) wherever possible! + From cd75e7f3411173a39d70b2387b75c4e8eb469078 Mon Sep 17 00:00:00 2001 From: Jon Tippens Date: Tue, 4 Jun 2019 16:29:23 -0700 Subject: [PATCH 02/47] Limit lines to 80 chars --- src/_guides/language/async-await.md | 215 +++++++++++++++++++--------- 1 file changed, 148 insertions(+), 67 deletions(-) diff --git a/src/_guides/language/async-await.md b/src/_guides/language/async-await.md index ff3a0b63e4..8a51546465 100644 --- a/src/_guides/language/async-await.md +++ b/src/_guides/language/async-await.md @@ -1,28 +1,20 @@ ---- - ---- - -# - - - - ## Asynchronous Dart Code: Future, async, and await - - ## Introduction +Welcome to the asynchronous Dart codelab! In this codelab you'll practice using +Dart to run asynchronous code via the `async` and `await` keywords. -Welcome to the asynchronous Dart codelab! In this codelab you'll practice using Dart to run asynchronous code via the `async` and `await` keywords. - -In addition to explanations, this codelab includes embedded editors that show you working code examples and coding exercises. You can use these editors to test your knowledge by completing the exercises. +In addition to explanations, this codelab includes embedded editors that show +you working code examples and coding exercises. You can use these editors to +test your knowledge by completing the exercises. Before you begin this codelab, you should: -* Have some experience writing asynchronous code -- for example, writing code that sends a request to a server and then handles a response +* Have some experience writing asynchronous code -- for example, writing code +that sends a request to a server and then handles a response When you finish this codelab, you'll know the following: @@ -30,26 +22,31 @@ When you finish this codelab, you'll know the following: * How to use the `await` keyword * When to use `async` and `await` in your code * How your code will be executed when you use the `async/await` keywords -* How to handle errors from an asynchronous call using `try/catch` expressions in async functions. -* Where to find more information for related to the `async/await` material covered in this codelab. +* How to handle errors from an asynchronous call using `try/catch` expressions +in async functions. +* Where to find more information for related to the `async/await` material +covered in this codelab. ## Why Async Matters - - - -Asynchronous operations let your program complete other work while waiting for an operation to finish. Some common processes that require asynchronous operations include: +Asynchronous operations let your program complete other work while waiting for +an operation to finish. Some common processes that require asynchronous +operations include: * Fetching data over a network * Writing to a database * Reading data from a file -In order to write code that implements these features, you will need to learn the Dart syntax for Futures, async, and await. In Dart you cannot use synchronous code to handle asynchronous operations. +In order to write code that implements these features, you will need to learn +the Dart syntax for Futures, async, and await. In Dart you cannot use +synchronous code to handle asynchronous operations. -Consider the following example that fails to print the desired user order to the console: +Consider the following example that fails to print the desired user order to the +console: -Note: this example shows how *not* to handle asynchronous code in dart. {:.fails-sa} +Note: this example shows how *not* to handle asynchronous code in dart. +{:.fails-sa} ``` String createOrderMessage () { @@ -71,24 +68,37 @@ main() { In the above code: -* `getUserOrder` is an asynchronous function that waits four seconds before returning a string describing the user's order: a large latte. (For a further explanation you can [find out more about Future.delayed](https://api.dartlang.org/stable/2.3.0/dart-async/Future/Future.delayed.html)) -* `createOrderMessage` calls `getUserOrder` as if it were a synchronous function -- it invokes `getUserOrder` and immediately prints the result. -* Since `getUserOrder` waits four seconds before returning the user's order, `createOrderMessage` never actually prints the user's order. Instead you can see `Instance of '_Future'` printed to the console as the value returned by `createOrderMessage().` +* `getUserOrder` is an asynchronous function that waits four seconds before +returning a string describing the user's order: a large latte. (For a further + explanation you can + [find out more about Future.delayed](https://api.dartlang.org/stable/2.3.0/dart-async/Future/Future.delayed.html)) +* `createOrderMessage` calls `getUserOrder` as if it were a synchronous function + -- it invokes `getUserOrder` and immediately prints the result. +* Since `getUserOrder` waits four seconds before returning the user's order, +`createOrderMessage` never actually prints the user's order. Instead you can see + `Instance of '_Future'` printed to the console as the value returned + by `createOrderMessage().` -What is a future, and how do we write code to handle the asynchronous function `getUserOrder`? +What is a future, and how do we write code to handle the asynchronous function + `getUserOrder`? ## Async in Dart: What is a Future? -In Dart, the result of an asynchronous operation is represented by a [Future](https://api.dartlang.org/stable/2.2.0/dart-async/Future-class.html) object. A future object can be in one of two states: uncompleted or completed. +In Dart, the result of an asynchronous operation is represented by a +[Future](https://api.dartlang.org/stable/2.2.0/dart-async/Future-class.html) +object. A future object can be in one of two states: uncompleted or completed. ### **Lifecycle of a Future Object** ### **Uncompleted** -When you invoke a function that returns a future, that function immediately returns a future object in an uncompleted state. While in its uncompleted state, a future object is simply waiting for asynchronous operations to finish or to throw an error. +When you invoke a function that returns a future, that function immediately +returns a future object in an uncompleted state. While in its uncompleted state, + a future object is simply waiting for asynchronous operations to finish or to + throw an error. ### **Completed ** @@ -96,13 +106,20 @@ There are two ways that a future object can complete: #### **Completed - Success** -If the asynchronous operations succeed, the future completes and returns a result of type T. For example, [Future](https://api.dartlang.org/stable/2.3.0/dart-async/Future-class.html)`` is the type signature for a future object that produces a string result. If a future produces a result that isn't a usable value, then the future's type is `Future`. +If the asynchronous operations succeed, the future completes and returns a +result of type T. For example, +[Future](https://api.dartlang.org/stable/2.3.0/dart-async/Future-class.html) +`` is the type signature for a future object that produces a string +result. If a future produces a result that isn't a usable value, then the +future's type is `Future`. #### **Completed - Error** -Instead of succeeding, if the asynchronous operations being performed by the function throw an error, the future completes and returns an error. +Instead of succeeding, if the asynchronous operations being performed by the +function throw an error, the future completes and returns an error. -To see this lifecycle at work consider what happens after you invoke the `getUserOrder` function: +To see this lifecycle at work consider what happens after you invoke the +`getUserOrder` function: ``` String createOrderMessage () { @@ -122,40 +139,57 @@ main() { `// Your order is: Instance of '_Future'` -* after 1 second has passed: the future is uncomplete - we cannot access the desired result yet +* after 1 second has passed: the future is uncomplete - we cannot access the +desired result yet ` Your order is: Instance of '_Future'` -* after 4 seconds have passed: the future completes, returning the desired result +* after 4 seconds have passed: the future completes, returning the desired +result `'Large Latte'` -But how do you access this result that completes 4 seconds later? In addition to providing future objects, Dart also provides a clean and easy way to handle their results -- the `async` and `await` keywords. +But how do you access this result that completes 4 seconds later? In addition +to providing future objects, Dart also provides a clean and easy way to handle +their results -- the `async` and `await` keywords. Quick Review: -* In Dart, the result of an asynchronous operation is represented by a [Future](https://api.dartlang.org/stable/2.2.0/dart-async/Future-class.html)`` object that produces a result of type `T`. For example, [Future](https://api.dartlang.org/stable/2.3.0/dart-async/Future-class.html)`` is the type signature for a future object that produces a string result. If a future produces a result that isn't a usable value, then the future's type is `Future`. +* In Dart, the result of an asynchronous operation is represented by a +[Future](https://api.dartlang.org/stable/2.2.0/dart-async/Future-class.html)`` +object that produces a result of type `T`. For example, +[Future](https://api.dartlang.org/stable/2.3.0/dart-async/Future-class.html)`` +is the type signature for a future object that produces a string result. If a +future produces a result that isn't a usable value, then the future's type is +`Future`. * A future can be in one of two states: uncompleted, or completed. -* A completed future can either (1) complete with a result or (2) complete with an error +* A completed future can either (1) complete with a result or (2) complete with +an error * When a function that returns a future is invoked, two things happen: 1. The function queues up work to be done and returns an uncompleted future. -2. Later, when the operation is finished, the future completes with a value or with an error. +2. Later, when the operation is finished, the future completes with a value or +with an error. ## Working with Futures in Dart: async and await -In the previous section you learned that, in Dart, future objects represent the results of asynchronous operations -- if a function does asynchronous work, it returns a future object. But how do we access the results of future objects when using asynchronous functions? +In the previous section you learned that, in Dart, future objects represent the +results of asynchronous operations -- if a function does asynchronous work, it +returns a future object. But how do we access the results of future objects when +using asynchronous functions? -The `async` and `await` keywords provide a declarative way to (1) define asynchronous functions and (2) access their results *after they have completed.* +The `async` and `await` keywords provide a declarative way to (1) define +asynchronous functions and (2) access their results *after they have completed.* -To define an `async` function: +To define an `async` function: -1. Add the `async` keyword after the function's parameters but before the function's body. +1. Add the `async` keyword after the function's parameters but before the + function's body. createOrderMessage () async { @@ -163,14 +197,21 @@ To define an `async` function: Future createOrderMessage () async { - *Note: You can * [use Future](https://dart.dev/guides/language/effective-dart/design#do-use-futurevoid-as-the-return-type-of-asynchronous-members-that-do-not-produce-values) * as the return type for asynchronous functions that don't return usable values. * + *Note: You can * [use + Future](https://dart.dev/guides/language/effective-dart/design#do-use-futurevoid-as-the-return-type-of-asynchronous-members-that-do-not-produce-values) * + as the return type for asynchronous functions that don't return usable values. + * -Once you have defined an async function, that function will return a future object. Using the await keyword, you can "wait" for the completed future to return either its value or its error. +Once you have defined an async function, that function will return a future +object. Using the await keyword, you can "wait" for the completed future to +return either its value or its error. String order = await getUserOrder(); -Remember, you can only use the `await` keyword within an `async` function body. The following example demonstrates how to convert `createOrderMessage` from synchronous to asynchronous: +Remember, you can only use the `await` keyword within an `async` function body. +The following example demonstrates how to convert `createOrderMessage` from +synchronous to asynchronous: ``` // BEFORE: handle a function that returns a string @@ -198,7 +239,9 @@ main() async { } ``` -* *Note: * [All functions return a value](https://dart.dev/guides/language/language-tour#return-values) * even if you don't explicitly use the * *`return`* * keyword. * +* *Note: * [All functions return a + value](https://dart.dev/guides/language/language-tour#return-values) * even + if you don't explicitly use the * *`return`* * keyword. * * *Note: Dart can * [infer the Future type](https://dart.dev/guides/language/sound-dart#type-inference) * for you. * @@ -213,7 +256,10 @@ This code has only three changes from the preceding implementation: -As of Dart 2.0, functions marked as `async` run synchronously until the first `await` keyword. This means that within an `async` function's body, all synchronous code is immediately executed. This is demonstrated in the following example: +As of Dart 2.0, functions marked as `async` run synchronously until the first +`await` keyword. This means that within an `async` function's body, all +synchronous code is immediately executed. This is demonstrated in the following +example: ``` void createOrderMessage () async { @@ -236,7 +282,9 @@ main() async { // Your order is: Large Latte ``` -Notice that the timing of the output shifts if we move the print statement "Awaiting user order" to the line after the first await keyword in `createOrderMessage`: +Notice that the timing of the output shifts if we move the print statement +"Awaiting user order" to the line after the first await keyword in +`createOrderMessage`: ``` void createOrderMessage () async { @@ -264,12 +312,22 @@ main() async { -The exercise below is created with partially completed code snippets as a failing unit test, and you will be writing code and make it pass. Verify your code by clicking the Run button. +The exercise below is created with partially completed code snippets as a +failing unit test, and you will be writing code and make it pass. Verify your +code by clicking the Run button. Add the following: -* Part 1: Add logic to the `reportUserRole` function so that it returns a Future that produces the String result ‘User role: !'. The can be obtained by calling the provided async function `getRole` which returns a `String` describing the user role. Example return value from `reportUserRole()`: `'User role: tester'` -* Part 2: Write an `async` function `reportLogins` that returns the string: ‘Total number of logins: '. The can be obtained by calling the provided asynchronous function `getLoginAmount`, which returns an `int` representing the number of times that the user has logged in. Example return value from `reportLogins(): 'Total number of logins: 57'` +* Part 1: Add logic to the `reportUserRole` function so that it returns a Future + that produces the String result ‘User role: !'. The can + be obtained by calling the provided async function `getRole` which returns a + `String` describing the user role. Example return value from + `reportUserRole()`: `'User role: tester'` +* Part 2: Write an `async` function `reportLogins` that returns the string: + ‘Total number of logins: '. The can be obtained + by calling the provided asynchronous function `getLoginAmount`, which returns + an `int` representing the number of times that the user has logged in. Example + return value from `reportLogins(): 'Total number of logins: 57'` ## Handling errors @@ -301,44 +359,67 @@ main() async { // Caught error: Cannot locate user order ``` -The try-catch code behaves in the same way with asynchronous code as it does with synchronous code: if the code within the `try` block throws an exception, the code inside the `catch` clause executes. +The try-catch code behaves in the same way with asynchronous code as it does +with synchronous code: if the code within the `try` block throws an exception, +the code inside the `catch` clause executes. ## Practice Handling Errors with async and awaitImplement code to accomplish the following: -* Make `changeUsername` call the provided asynchronous function `getNewUsername`, and return its result -* `changeUsername` must catch and return any errors thrown by getNewUsername, prefixing the returned error with the following string: `Error:` -* Example return value from `changeUsername` when `getNewUsername` throws an error: `Error: Username must contain only alphanumeric values` +* Make `changeUsername` call the provided asynchronous function + `getNewUsername`, and return its result +* `changeUsername` must catch and return any errors thrown by getNewUsername, + prefixing the returned error with the following string: `Error:` +* Example return value from `changeUsername` when `getNewUsername` throws an + error: `Error: Username must contain only alphanumeric values` ## Putting It All Together -Now it's time to sum up what you've learned in one final exercise. In the following snippet, write the following: +Now it's time to sum up what you've learned in one final exercise. In the +following snippet, write the following: -* Part1: Write a function `addHello.` `addHello` should take a single string argument, and return that argument surrounded by the text ‘Hello !' +* Part1: Write a function `addHello.` `addHello` should take a single string + argument, and return that argument surrounded by the text ‘Hello !' * Part2: Write a function `greetUser` that takes no arguments -* To obtain the username, `greetUser` should call the provided async function `getUsername`, which waits for 1 second before returning a string -* `greetUser` should create a greeting for the user by calling `addHello,` passing it the username, and returning the result. For example, if the username is ‘Jenny' `greetUser` should create and return the greeting "Hello Jenny!" +* To obtain the username, `greetUser` should call the provided async function + `getUsername`, which waits for 1 second before returning a string +* `greetUser` should create a greeting for the user by calling `addHello,` + passing it the username, and returning the result. For example, if the + username is ‘Jenny' `greetUser` should create and return the greeting "Hello + Jenny!" * Part3: Write a function `sayGoodbye` that takes no arguments -* Within its function body, `sayGoodbye` should call the provided async function `logoutUser` which takes no arguments. +* Within its function body, `sayGoodbye` should call the provided async function + `logoutUser` which takes no arguments. * `sayGoodbye` should catch any errors thrown by `logoutUser` -* If `logoutUser` succeeds, `sayGoodbye` should return the string " Thanks! See you next time!" where is the String value returned by calling `logoutUser` +* If `logoutUser` succeeds, `sayGoodbye` should return the string " + Thanks! See you next time!" where is the String value returned by + calling `logoutUser` +If you want multiple parts of Dart code to run concurrently, you can run them in +separate isolates. (Web apps use *workers* instead of isolates.) Multiple +isolates run at the same time, usually each on its own CPU core. Isolates don't +share memory, and the only way they can interact is by sending messages to each +other. Find Out More * [Futures](https://www.dartlang.org/tutorials/language/futures) * [The Event Loop in Dart](https://webdev.dartlang.org/articles/performance/event-loop) * [Isolates](https://api.dartlang.org/stable/2.2.0/dart-isolate/dart-isolate-library.html) -* Read about [Dart's type system](https://dart.dev/guides/language/sound-dart) for more examples of type signatures with futures. You should [prefer signatures in function type annotations](https://dart.dev/guides/language/effective-dart/design#prefer-signatures-in-function-type-annotations) wherever possible! - +* Read about [Dart's type system](https://dart.dev/guides/language/sound-dart) + for more examples of type signatures with futures. You should [prefer + signatures in function type + annotations](https://dart.dev/guides/language/effective-dart/design#prefer-signatures-in-function-type-annotations) + wherever possible! From 33a671b3ce23b1719387c8fd7f867ea223e734ad Mon Sep 17 00:00:00 2001 From: Jon Tippens Date: Wed, 5 Jun 2019 13:18:03 -0700 Subject: [PATCH 03/47] Round 1 of revisions: - add futures codelab to sidenav - add futures codelab to /codelabs page - update 'url' global to dart.dev - move futures codelab to /codelabs/async-await (formerly incorrectly placed in /language) - sundry content corrections in futures codelab --- _config.yml | 2 +- src/_data/side-nav.yml | 2 + .../async-await/index.md} | 179 +++++++++--------- src/codelabs/index.md | 4 + 4 files changed, 97 insertions(+), 90 deletions(-) rename src/{_guides/language/async-await.md => codelabs/async-await/index.md} (72%) diff --git a/_config.yml b/_config.yml index edcbe29a91..4638292922 100644 --- a/_config.yml +++ b/_config.yml @@ -1,7 +1,7 @@ # Site settings title: Dart description: Dart is a platform for building structured apps. It includes a language, a VM, libraries, tools, and compilers to many targets, including JavaScript. -url: https://www.dartlang.org +url: https://dart.dev dev-url: https://dartlang-org-dev.firebaseapp.com repo: this: https://github.com/dart-lang/site-www diff --git a/src/_data/side-nav.yml b/src/_data/side-nav.yml index c245b48506..665b73c83c 100644 --- a/src/_data/side-nav.yml +++ b/src/_data/side-nav.yml @@ -12,6 +12,8 @@ permalink: /codelabs - title: Cheatsheet codelab permalink: /codelabs/dart-cheatsheet + - title: Futures Async Await + permalink: /codelabs/async-await - title: Tutorials urlExactMatch: true match-page-url-exactly: true diff --git a/src/_guides/language/async-await.md b/src/codelabs/async-await/index.md similarity index 72% rename from src/_guides/language/async-await.md rename to src/codelabs/async-await/index.md index 8a51546465..15ba83f5b9 100644 --- a/src/_guides/language/async-await.md +++ b/src/codelabs/async-await/index.md @@ -1,10 +1,16 @@ -## Asynchronous Dart Code: Future, async, and await +--- +title: Asynchronous Dart code - futures, async, and await +description: A series of explanations and exercises for writing asynchronous code in Dart +date: 2019-06-07 +tags: [ future, async, await, asynchronous, try, catch, error ] +--- +## Asynchronous Dart code: future, async, and await ## Introduction -Welcome to the asynchronous Dart codelab! In this codelab you'll practice using +Welcome to the asynchronous Dart codelab! In this codelab you practice using Dart to run asynchronous code via the `async` and `await` keywords. In addition to explanations, this codelab includes embedded editors that show @@ -13,22 +19,22 @@ test your knowledge by completing the exercises. Before you begin this codelab, you should: -* Have some experience writing asynchronous code -- for example, writing code -that sends a request to a server and then handles a response +* Have some experience writing asynchronous code. (For example, send a request + to a server and handle the response) When you finish this codelab, you'll know the following: * How to use the `async` keyword * How to use the `await` keyword * When to use `async` and `await` in your code -* How your code will be executed when you use the `async/await` keywords +* How your code executes when using the `async/await` keywords * How to handle errors from an asynchronous call using `try/catch` expressions in async functions. -* Where to find more information for related to the `async/await` material +* Where to find more information for the `async/await` material covered in this codelab. -## Why Async Matters +## Why async matters Asynchronous operations let your program complete other work while waiting for an operation to finish. Some common processes that require asynchronous @@ -38,17 +44,16 @@ operations include: * Writing to a database * Reading data from a file -In order to write code that implements these features, you will need to learn -the Dart syntax for Futures, async, and await. In Dart you cannot use -synchronous code to handle asynchronous operations. +To implement these features, you will need to learn the Dart syntax for +futures, async, and await. In Dart you cannot use synchronous code to handle +asynchronous operations. Consider the following example that fails to print the desired user order to the console: -Note: this example shows how *not* to handle asynchronous code in dart. -{:.fails-sa} +```dart +// Note: this example shows how *not* to handle asynchronous code in dart. -``` String createOrderMessage () { var order = getUserOrder(); return 'Your order is: $order'; @@ -62,49 +67,46 @@ Future getUserOrder() { main() { print(createOrderMessage()); } +`// Your order is: Instance of '_Future'` ``` -`// Your order is: Instance of '_Future'` In the above code: -* `getUserOrder` is an asynchronous function that waits four seconds before +* `getUserOrder` is an asynchronous function that waits four seconds before returning a string describing the user's order: a large latte. (For a further - explanation you can - [find out more about Future.delayed](https://api.dartlang.org/stable/2.3.0/dart-async/Future/Future.delayed.html)) +explanation you can [find out more about +Future.delayed](https://api.dartlang.org/stable/2.3.0/dart-async/Future/Future.delayed.html)) * `createOrderMessage` calls `getUserOrder` as if it were a synchronous function -- it invokes `getUserOrder` and immediately prints the result. -* Since `getUserOrder` waits four seconds before returning the user's order, -`createOrderMessage` never actually prints the user's order. Instead you can see - `Instance of '_Future'` printed to the console as the value returned - by `createOrderMessage().` +* Since `getUserOrder` waits four seconds before returning the user's order, +`createOrderMessage` never actually prints the user's order. Instead the console +prints the value that is immediately returned by `createOrderMessage` which +turns out to be `Instance of '_Future'`. -What is a future, and how do we write code to handle the asynchronous function +What is a future, and how do you write code to handle the asynchronous function `getUserOrder`? -## Async in Dart: What is a Future? - - +## Async in Dart: What is a future? -In Dart, the result of an asynchronous operation is represented by a +In Dart, a [Future](https://api.dartlang.org/stable/2.2.0/dart-async/Future-class.html) -object. A future object can be in one of two states: uncompleted or completed. +represents the result of an asynchronous operation. A future object can be in +one of two states: uncompleted or completed. -### **Lifecycle of a Future Object** - -### **Uncompleted** +### Uncompleted When you invoke a function that returns a future, that function immediately returns a future object in an uncompleted state. While in its uncompleted state, a future object is simply waiting for asynchronous operations to finish or to throw an error. -### **Completed ** +### Completed There are two ways that a future object can complete: -#### **Completed - Success** +#### Success If the asynchronous operations succeed, the future completes and returns a result of type T. For example, @@ -113,12 +115,12 @@ result of type T. For example, result. If a future produces a result that isn't a usable value, then the future's type is `Future`. -#### **Completed - Error** +#### Error -Instead of succeeding, if the asynchronous operations being performed by the +If the asynchronous operations being performed by the function throw an error, the future completes and returns an error. -To see this lifecycle at work consider what happens after you invoke the +To see this lifecycle at work consider what happens after invoking the `getUserOrder` function: ``` @@ -139,7 +141,7 @@ main() { `// Your order is: Instance of '_Future'` -* after 1 second has passed: the future is uncomplete - we cannot access the +* after 1 second has passed: the future hasn't been completed - you can't access the desired result yet ` Your order is: Instance of '_Future'` @@ -150,41 +152,39 @@ result `'Large Latte'` -But how do you access this result that completes 4 seconds later? In addition +How do you access this result that completes 4 seconds later? In addition to providing future objects, Dart also provides a clean and easy way to handle their results -- the `async` and `await` keywords. Quick Review: -* In Dart, the result of an asynchronous operation is represented by a -[Future](https://api.dartlang.org/stable/2.2.0/dart-async/Future-class.html)`` -object that produces a result of type `T`. For example, +* In Dart, a +[Future](https://api.dartlang.org/stable/2.2.0/dart-async/Future-class.html) +produces a result of type ``. For example, [Future](https://api.dartlang.org/stable/2.3.0/dart-async/Future-class.html)`` -is the type signature for a future object that produces a string result. If a +is the type signature for a future object that produces a string result. If a future produces a result that isn't a usable value, then the future's type is -`Future`. +`Future`. * A future can be in one of two states: uncompleted, or completed. * A completed future can either (1) complete with a result or (2) complete with -an error -* When a function that returns a future is invoked, two things happen: +an error. +* When you invoke a function that returns a future, two things happen: 1. The function queues up work to be done and returns an uncompleted future. 2. Later, when the operation is finished, the future completes with a value or with an error. -## Working with Futures in Dart: async and await - - +## Working with futures in Dart: async and await In the previous section you learned that, in Dart, future objects represent the results of asynchronous operations -- if a function does asynchronous work, it -returns a future object. But how do we access the results of future objects when +returns a future object. But how to access the results of future objects when using asynchronous functions? -The `async` and `await` keywords provide a declarative way to (1) define -asynchronous functions and (2) access their results *after they have completed.* - +The `async` and `await` keywords provide a declarative way to: +1. Define asynchronous functions +2. Access their results *after they have completed.* To define an `async` function: @@ -193,18 +193,19 @@ To define an `async` function: createOrderMessage () async { -2. Update the function's type signature to return a future. In the following example, we define an `async` function that completes with a string. +2. Update the function's type signature to return a future. The following +example defines an `async` function that completes with a string. - Future createOrderMessage () async { +[[[ Example ]]] - *Note: You can * [use +{{site.alert.note}} + Note: You can [use Future](https://dart.dev/guides/language/effective-dart/design#do-use-futurevoid-as-the-return-type-of-asynchronous-members-that-do-not-produce-values) * as the return type for asynchronous functions that don't return usable values. - * - + {{site.alert.end}} -Once you have defined an async function, that function will return a future -object. Using the await keyword, you can "wait" for the completed future to +Once you've defined an async function, that function returns a future +object. Use the `await` keyword to "wait" for the completed future to return either its value or its error. String order = await getUserOrder(); @@ -239,22 +240,23 @@ main() async { } ``` -* *Note: * [All functions return a - value](https://dart.dev/guides/language/language-tour#return-values) * even - if you don't explicitly use the * *`return`* * keyword. * -* *Note: Dart can * [infer the Future type](https://dart.dev/guides/language/sound-dart#type-inference) * for you. -* +{{site.alert.note}} +Note: [All functions return a + value](https://dart.dev/guides/language/language-tour#return-values) even + if you don't explicitly use the `return` keyword. +{{site.alert.end}} + +{{site.alert.note}} +Note: Dart can [infer the Future type](https://dart.dev/guides/language/sound-dart#type-inference) for you. +{{site.alert.end}} This code has only three changes from the preceding implementation: -1. Mark the return type for `createOrderMessage` with `Future` -2. Add **`async`** before the method body (the `createOrderMessage` and the `main` method) -3. Add **`await`** before the calling the asynchronous function (before we invoke `getUserOrder` and `createOrderMessage`) - - -## Execution Flow with async and await - +1. Mark the return type for `createOrderMessage` with `Future`. +2. Add **`async`** before the method body (the `createOrderMessage` and the `main` method). +3. Add **`await`** before the calling the asynchronous function (before invoking `getUserOrder` and `createOrderMessage`). +## Execution flow with async and await As of Dart 2.0, functions marked as `async` run synchronously until the first `await` keyword. This means that within an `async` function's body, all @@ -308,7 +310,7 @@ main() async { ``` -## Practice Using async and await +## Practice using async and await @@ -334,7 +336,7 @@ Add the following: -`Async` functions can handle errors using try-catch: +Handle errors in an `async` function by using try / catch: ``` void createOrderMessage () async { @@ -347,7 +349,7 @@ void createOrderMessage () async { } Future getUserOrder() { - // Imagine that this function is more complex and throws an exception + // Imagine that this function is more complex and throws an exception. var str = Future.delayed(Duration(seconds: 4), () => throw 'Cannot locate user order'); return str; } @@ -364,9 +366,8 @@ with synchronous code: if the code within the `try` block throws an exception, the code inside the `catch` clause executes. -## Practice Handling Errors with async and awaitImplement code to accomplish the following: - - +## Practice handling errors +Use `async` and `await` to accomplish the following: * Make `changeUsername` call the provided asynchronous function `getNewUsername`, and return its result @@ -376,12 +377,9 @@ the code inside the `catch` clause executes. error: `Error: Username must contain only alphanumeric values` -## Putting It All Together - - +## Putting it all together -Now it's time to sum up what you've learned in one final exercise. In the -following snippet, write the following: +It's time to sum up what you've learned in one final exercise. Write the following: * Part1: Write a function `addHello.` `addHello` should take a single string argument, and return that argument surrounded by the text ‘Hello !' @@ -402,10 +400,12 @@ following snippet, write the following: -Find Out More +### Find out more -* [Futures](https://www.dartlang.org/tutorials/language/futures) -* [The Event Loop in Dart](https://webdev.dartlang.org/articles/performance/event-loop) -* [Isolates](https://api.dartlang.org/stable/2.2.0/dart-isolate/dart-isolate-library.html) -* Read about [Dart's type system](https://dart.dev/guides/language/sound-dart) +* Try [other Dart codelabs](/codelabs). +* Play with [DartPad.]({{site.dartpad}}) +* The [Futures]({{site.url}}/tutorials/language/futures) tutorial +* [Isolates]({{site.dart_api}}/stable/2.2.0/dart-isolate/dart-isolate-library.html) +* Read about [Dart's type system]({{site.url}}/guides/language/sound-dart) for more examples of type signatures with futures. You should [prefer signatures in function type - annotations](https://dart.dev/guides/language/effective-dart/design#prefer-signatures-in-function-type-annotations) + annotations]({{site.url}}/guides/language/effective-dart/design#prefer-signatures-in-function-type-annotations) wherever possible! diff --git a/src/codelabs/index.md b/src/codelabs/index.md index 3689e94262..aed68408ac 100644 --- a/src/codelabs/index.md +++ b/src/codelabs/index.md @@ -20,6 +20,10 @@ Use the latest, experimental version of DartPad to learn, remind yourself about, or test your knowledge of some of the most commonly used, yet unique features of the Dart language. +### [Futures Async & Await](/codelabs/async-await) + +Use DartPad to learn how to write asynchronous code in Dart via futures and the +async/await keywords. ## Flutter From 3934ee60f30e42f89eba199f25e66815a285a46b Mon Sep 17 00:00:00 2001 From: Jon Tippens Date: Wed, 5 Jun 2019 16:04:08 -0700 Subject: [PATCH 04/47] Add more updates per language comments/suggestions review feedback --- src/codelabs/async-await/index.md | 60 +++++++++++++++---------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/src/codelabs/async-await/index.md b/src/codelabs/async-await/index.md index 15ba83f5b9..64ad32939a 100644 --- a/src/codelabs/async-await/index.md +++ b/src/codelabs/async-await/index.md @@ -5,11 +5,10 @@ date: 2019-06-07 tags: [ future, async, await, asynchronous, try, catch, error ] --- -## Asynchronous Dart code: future, async, and await +# Asynchronous Dart code: future, async, and await ## Introduction - Welcome to the asynchronous Dart codelab! In this codelab you practice using Dart to run asynchronous code via the `async` and `await` keywords. @@ -51,7 +50,9 @@ asynchronous operations. Consider the following example that fails to print the desired user order to the console: -```dart +{:.fails-sa} + +{% prettify dart %} // Note: this example shows how *not* to handle asynchronous code in dart. String createOrderMessage () { @@ -68,7 +69,7 @@ main() { print(createOrderMessage()); } `// Your order is: Instance of '_Future'` -``` +{% endprettify %} In the above code: @@ -81,7 +82,7 @@ Future.delayed](https://api.dartlang.org/stable/2.3.0/dart-async/Future/Future.d -- it invokes `getUserOrder` and immediately prints the result. * Since `getUserOrder` waits four seconds before returning the user's order, `createOrderMessage` never actually prints the user's order. Instead the console -prints the value that is immediately returned by `createOrderMessage` which +prints the value immediately returned by `createOrderMessage` which turns out to be `Instance of '_Future'`. What is a future, and how do you write code to handle the asynchronous function @@ -92,8 +93,8 @@ What is a future, and how do you write code to handle the asynchronous function In Dart, a [Future](https://api.dartlang.org/stable/2.2.0/dart-async/Future-class.html) -represents the result of an asynchronous operation. A future object can be in -one of two states: uncompleted or completed. +represents the result of an asynchronous operation. A future object has +two states: uncompleted or completed. ### Uncompleted @@ -110,8 +111,7 @@ There are two ways that a future object can complete: If the asynchronous operations succeed, the future completes and returns a result of type T. For example, -[Future](https://api.dartlang.org/stable/2.3.0/dart-async/Future-class.html) -`` is the type signature for a future object that produces a string +`Future` is the type signature for a future object that produces a string result. If a future produces a result that isn't a usable value, then the future's type is `Future`. @@ -196,25 +196,25 @@ To define an `async` function: 2. Update the function's type signature to return a future. The following example defines an `async` function that completes with a string. -[[[ Example ]]] - -{{site.alert.note}} - Note: You can [use - Future](https://dart.dev/guides/language/effective-dart/design#do-use-futurevoid-as-the-return-type-of-asynchronous-members-that-do-not-produce-values) * +
+ Note: You can + [use Future\]({{url}}/guides/language/effective-dart/design#do-use-futurevoid-as-the-return-type-of-asynchronous-members-that-do-not-produce-values) as the return type for asynchronous functions that don't return usable values. - {{site.alert.end}} +
Once you've defined an async function, that function returns a future object. Use the `await` keyword to "wait" for the completed future to return either its value or its error. - String order = await getUserOrder(); +```dart +String order = await getUserOrder(); +``` Remember, you can only use the `await` keyword within an `async` function body. The following example demonstrates how to convert `createOrderMessage` from synchronous to asynchronous: -``` +```dart // BEFORE: handle a function that returns a string String createOrderMessage () { @@ -240,15 +240,15 @@ main() async { } ``` -{{site.alert.note}} +
Note: [All functions return a value](https://dart.dev/guides/language/language-tour#return-values) even if you don't explicitly use the `return` keyword. -{{site.alert.end}} +
-{{site.alert.note}} -Note: Dart can [infer the Future type](https://dart.dev/guides/language/sound-dart#type-inference) for you. -{{site.alert.end}} +
+Note: Dart can [infer the Future\ type](https://dart.dev/guides/language/sound-dart#type-inference) for you. +
This code has only three changes from the preceding implementation: @@ -260,10 +260,10 @@ This code has only three changes from the preceding implementation: As of Dart 2.0, functions marked as `async` run synchronously until the first `await` keyword. This means that within an `async` function's body, all -synchronous code is immediately executed. This is demonstrated in the following +synchronous code immediately executes. This is demonstrated in the following example: -``` +```dart void createOrderMessage () async { print('Awaiting user order...'); var order = await getUserOrder(); @@ -284,11 +284,11 @@ main() async { // Your order is: Large Latte ``` -Notice that the timing of the output shifts if we move the print statement -"Awaiting user order" to the line after the first await keyword in +Notice that the timing of the output shifts if the print statement +"Awaiting user order" moves to the line after the first `await` keyword in `createOrderMessage`: -``` +```dart void createOrderMessage () async { var order = await getUserOrder(); print('Awaiting user order...'); @@ -338,7 +338,7 @@ Add the following: Handle errors in an `async` function by using try / catch: -``` +```dart void createOrderMessage () async { try { var order = await getUserOrder(); @@ -400,12 +400,12 @@ It's time to sum up what you've learned in one final exercise. Write the followi * Try [other Dart codelabs](/codelabs). * Play with [DartPad.]({{site.dartpad}}) -* The [Futures]({{site.url}}/tutorials/language/futures) tutorial -* [Isolates]({{site.dart_api}}/stable/2.2.0/dart-isolate/dart-isolate-library.html) -* Read about [Dart's type system]({{site.url}}/guides/language/sound-dart) +* The [Futures](/tutorials/language/futures) tutorial +* Read about [Dart's type system](/guides/language/sound-dart) for more examples of type signatures with futures. You should [prefer signatures in function type - annotations]({{site.url}}/guides/language/effective-dart/design#prefer-signatures-in-function-type-annotations) + annotations](/guides/language/effective-dart/design#prefer-signatures-in-function-type-annotations) wherever possible! From b587b7faf41fd1c3eb81554bff040a023e16c943 Mon Sep 17 00:00:00 2001 From: Jon Tippens Date: Wed, 5 Jun 2019 17:10:50 -0700 Subject: [PATCH 06/47] Configure site.alert templates and update futures codelab w/ templates --- _config.yml | 26 +++++++++++++++++++ src/codelabs/async-await/index.md | 43 +++++++++++++++---------------- 2 files changed, 47 insertions(+), 22 deletions(-) diff --git a/_config.yml b/_config.yml index 4638292922..4d9bd08ee8 100644 --- a/_config.yml +++ b/_config.yml @@ -85,6 +85,8 @@ custom: ext: zip editor-ext: zip + + # Build settings assets: @@ -95,6 +97,30 @@ assets: future: true # In support of https://github.com/dart-lang/site-www/issues/1111 +## Site-wide shorthands + +os-list: [Windows, macOS, Linux] + +alert: + important: >- +