Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(55)

Side by Side Diff: src/site/articles/event-loop/index.markdown

Issue 27412003: runAsync name change (Closed) Base URL: https://github.com/dart-lang/dartlang.org.git@master
Patch Set: add links to event loop article; add update date Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 --- 1 ---
2 layout: default 2 layout: default
3 title: "The Event Loop and Dart" 3 title: "The Event Loop and Dart"
4 description: "Learn how Dart handles the event queue and microtask queue, so you can write better asynchronous code with fewer surprises." 4 description: "Learn how Dart handles the event queue and microtask queue, so you can write better asynchronous code with fewer surprises."
5 rel: 5 rel:
6 author: kathy-walrath 6 author: kathy-walrath
7 has-permalinks: true 7 has-permalinks: true
8 article: 8 article:
9 written_on: 2013-09-30 9 written_on: 2013-09-30
10 updated_on: 2013-10-22
10 collection: performance 11 collection: performance
11 --- 12 ---
12 13
13 # {{ page.title }} 14 # {{ page.title }}
14 15
15 _Written by Kathy Walrath 16 _Written by Kathy Walrath
16 <br> 17 <br>
17 September 2013_ 18 September 2013 (updated October 2013)_
18 19
19 Asynchronous code is everywhere in Dart. 20 Asynchronous code is everywhere in Dart.
20 Many library functions return Future objects, 21 Many library functions return Future objects,
21 and you can register handlers to respond to events such as 22 and you can register handlers to respond to events such as
22 mouse clicks, file I/O completions, and timer expirations. 23 mouse clicks, file I/O completions, and timer expirations.
23 24
24 This article describes Dart’s event loop architecture, 25 This article describes Dart’s event loop architecture,
25 so that you can write better asynchronous code with fewer surprises. 26 so that you can write better asynchronous code with fewer surprises.
26 You’ll learn options for scheduling future tasks, 27 You’ll learn options for scheduling future tasks,
27 and you’ll be able to predict the order of execution. 28 and you’ll be able to predict the order of execution.
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after
138 Once both queues are empty and no more events are expected, 139 Once both queues are empty and no more events are expected,
139 the app’s _embedder_ (such as the browser or a test framework) 140 the app’s _embedder_ (such as the browser or a test framework)
140 can dispose of the app. 141 can dispose of the app.
141 142
142 <aside class="alert alert-info" markdown="1"> 143 <aside class="alert alert-info" markdown="1">
143 **Note:** 144 **Note:**
144 If a web app’s user closes its window, 145 If a web app’s user closes its window,
145 then the web app might exit before its event queue is empty. 146 then the web app might exit before its event queue is empty.
146 </aside> 147 </aside>
147 148
148 ![flowchart: main() -> microtasks -> next event -> microtasks -> ....](images/bo th-queues.png) 149 ![flowchart: main() -> microtasks -> next event -> microtasks -> ...](images/bot h-queues.png)
149 150
150 <aside class="alert alert-warning" markdown="1"> 151 <aside class="alert alert-warning" markdown="1">
151 **Important:** 152 **Important:**
152 While the event loop is executing tasks from the microtask queue, 153 While the event loop is executing tasks from the microtask queue,
153 the event queue is stuck: 154 the event queue is stuck:
154 the app can’t 155 the app can’t
155 draw graphics, handle mouse clicks, react to I/O, and so on. 156 draw graphics, handle mouse clicks, react to I/O, and so on.
156 </aside> 157 </aside>
157 158
158 Although you can predict the _order_ of task execution, 159 Although you can predict the _order_ of task execution,
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
206 process other events from the event queue. 207 process other events from the event queue.
207 The next section gives details on scheduling code to run later. 208 The next section gives details on scheduling code to run later.
208 209
209 ## How to schedule a task 210 ## How to schedule a task
210 211
211 When you need to specify some code to be executed later, 212 When you need to specify some code to be executed later,
212 you can use the following APIs provided by the dart:async library: 213 you can use the following APIs provided by the dart:async library:
213 214
214 1. The **Future** class, 215 1. The **Future** class,
215 which adds an item to the end of the **event queue**. 216 which adds an item to the end of the **event queue**.
216 1. The top-level **runAsync()** function, 217 1. The top-level **scheduleMicrotask()** function,
217 which adds an item to the end of the **microtask queue**. 218 which adds an item to the end of the **microtask queue**.
218 219
220 <aside class="alert alert-info" markdown="1">
221 **Note:**
222 The **scheduleMicrotask()** function used to be named **runAsync()**.
223 (See the [announcement](https://groups.google.com/a/dartlang.org/forum/#!msg/mis c/7sAIhWXfIKQ/PzYJy1QqtWUJ).)
224 </aside>
225
219 Examples of using these APIs are in the next section under 226 Examples of using these APIs are in the next section under
220 [Event queue: new Future()](#event-queue-new-future) and 227 [Event queue: new Future()](#event-queue-new-future) and
221 [Microtask queue: runAsync()](#microtask-queue-runasync). 228 [Microtask queue: scheduleMicrotask()](#microtask-queue).
222 229
223 ### Use the appropriate queue (usually: the event queue) 230 ### Use the appropriate queue (usually: the event queue)
224 231
225 Whenever possible, schedule tasks on the event queue, with Future. 232 Whenever possible, schedule tasks on the event queue, with Future.
226 Using the event queue helps keep the the microtask queue short, 233 Using the event queue helps keep the the microtask queue short,
227 reducing the likelihood of the microtask queue starving the event queue. 234 reducing the likelihood of the microtask queue starving the event queue.
228 235
229 If a task absolutely must complete before 236 If a task absolutely must complete before
230 any items from the event queue are handled, 237 any items from the event queue are handled,
231 then you should usually just execute the function immediately. 238 then you should usually just execute the function immediately.
232 If you can’t, then use runAsync() to add an item to the microtask queue. 239 If you can’t, then use scheduleMicrotask() to
240 add an item to the microtask queue.
233 For example, in a web app use a microtask to 241 For example, in a web app use a microtask to
234 avoid prematurely releasing a js-interop proxy or 242 avoid prematurely releasing a js-interop proxy or
235 ending an IndexedDB transaction or event handler. 243 ending an IndexedDB transaction or event handler.
236 244
237 ![shows chain of event handler execution, with tasks added using Future and runA sync().](images/scheduling-tasks.png) 245 ![shows chain of event handler execution, with tasks added using Future and sche duleMicrotask().](images/scheduling-tasks.png)
238 246
239 247
240 #### Event queue: new Future() 248 #### Event queue: new Future()
241 249
242 To schedule a task on the event queue, 250 To schedule a task on the event queue,
243 use `new Future()` or `new Future.delayed()`. 251 use `new Future()` or `new Future.delayed()`.
244 These are two of the 252 These are two of the
245 [Future](http://api.dartlang.org/dart_async/Future.html) 253 [Future](http://api.dartlang.org/dart_async/Future.html)
246 constructors defined in the dart:async library. 254 constructors defined in the dart:async library.
247 255
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
315 and _that_ task executes the function passed into then(). 323 and _that_ task executes the function passed into then().
316 1. The **Future()** and **Future.delayed()** constructors 324 1. The **Future()** and **Future.delayed()** constructors
317 don’t complete immediately; 325 don’t complete immediately;
318 they add an item to the event queue. 326 they add an item to the event queue.
319 1. The **Future.value()** constructor completes in a microtask, 327 1. The **Future.value()** constructor completes in a microtask,
320 similar to #2. 328 similar to #2.
321 1. The **Future.sync()** constructor executes its function argument immediately 329 1. The **Future.sync()** constructor executes its function argument immediately
322 and (unless that function returns a Future) 330 and (unless that function returns a Future)
323 completes in a microtask, similar to #2. 331 completes in a microtask, similar to #2.
324 332
325 #### Microtask queue: runAsync() 333 #### Microtask queue: scheduleMicrotask()
326 334
327 The dart:async library defines runAsync() as a top-level function. 335 The dart:async library defines scheduleMicrotask() as a top-level function.
328 You can call runAsync() like this: 336 You can call scheduleMicrotask() like this:
329 337
330 {% prettify dart %} 338 {% prettify dart %}
331 runAsync(() { 339 scheduleMicrotask(() {
332 // ...code goes here... 340 // ...code goes here...
333 }); 341 });
334 {% endprettify %} 342 {% endprettify %}
335 343
336 Due to bugs [9001](https://code.google.com/p/dart/issues/detail?id=9001) 344 Due to bugs [9001](https://code.google.com/p/dart/issues/detail?id=9001)
337 and [9002](https://code.google.com/p/dart/issues/detail?id=9002), 345 and [9002](https://code.google.com/p/dart/issues/detail?id=9002),
338 the first call to runAsync() schedules a task on the event queue; 346 the first call to scheduleMicrotask() schedules a task on the event queue;
339 this task creates the microtask queue and 347 this task creates the microtask queue and
340 enqueues the function specified to runAsync(). 348 enqueues the function specified to scheduleMicrotask().
341 As long as the microtask queue has at least one entry, 349 As long as the microtask queue has at least one entry,
342 subsequent calls to runAsync() correctly add to the microtask queue. 350 subsequent calls to scheduleMicrotask() correctly add to the microtask queue.
343 Once the microtask queue is empty, 351 Once the microtask queue is empty,
344 it must be created again the next time runAsync() is called. 352 it must be created again the next time scheduleMicrotask() is called.
345 353
346 The upshot of these bugs: 354 The upshot of these bugs:
347 The first task that you schedule with runAsync() seems 355 The first task that you schedule with scheduleMicrotask() seems
348 like it’s on the event queue. 356 like it’s on the event queue.
349 357
350 A workaround is to put your first call to runAsync() before 358 A workaround is to put your first call to scheduleMicrotask() before
351 your first call to new Future(). 359 your first call to new Future().
352 This creates the microtask queue before 360 This creates the microtask queue before
353 executing other tasks on the event queue. 361 executing other tasks on the event queue.
354 However, it doesn’t stop external events from being added to the event queue. 362 However, it doesn’t stop external events from being added to the event queue.
355 It also doesn’t help when you have a delayed task. 363 It also doesn’t help when you have a delayed task.
356 364
357 Another way to add a task to the microtask queue is 365 Another way to add a task to the microtask queue is
358 to invoke then() on a Future that’s already complete. 366 to invoke then() on a Future that’s already complete.
359 See the previous section for more information. 367 See the previous section for more information.
360 368
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
398 Still, won’t you feel smart if you can answer these questions correctly? 406 Still, won’t you feel smart if you can answer these questions correctly?
399 407
400 ### Question #1 408 ### Question #1
401 409
402 What does this sample print out? 410 What does this sample print out?
403 411
404 {% prettify dart %} 412 {% prettify dart %}
405 import 'dart:async'; 413 import 'dart:async';
406 main() { 414 main() {
407 print('main #1 of 2'); 415 print('main #1 of 2');
408 runAsync(() => print('runAsync #1 of 2')); 416 scheduleMicrotask(() => print('microtask #1 of 2'));
409 417
410 new Future.delayed(new Duration(seconds:1), 418 new Future.delayed(new Duration(seconds:1),
411 () => print('future #1 (delayed)')); 419 () => print('future #1 (delayed)'));
412 new Future(() => print('future #2 of 3')); 420 new Future(() => print('future #2 of 3'));
413 new Future(() => print('future #3 of 3')); 421 new Future(() => print('future #3 of 3'));
414 422
415 runAsync(() => print('runAsync #2 of 2')); 423 scheduleMicrotask(() => print('microtask #2 of 2'));
416 424
417 print('main #2 of 2'); 425 print('main #2 of 2');
418 } 426 }
419 {% endprettify %} 427 {% endprettify %}
420 428
421 The answer: 429 The answer:
422 430
423 <pre> 431 <pre>
424 main #1 of 2 432 main #1 of 2
425 main #2 of 2 433 main #2 of 2
426 runAsync #1 of 2 434 microtask #1 of 2
427 runAsync #2 of 2 435 microtask #2 of 2
428 future #2 of 3 436 future #2 of 3
429 future #3 of 3 437 future #3 of 3
430 future #1 (delayed) 438 future #1 (delayed)
431 </pre> 439 </pre>
432 440
433 That order should be what you expected, 441 That order should be what you expected,
434 since the example’s code executes in three batches: 442 since the example’s code executes in three batches:
435 443
436 1. code in the main() function 444 1. code in the main() function
437 1. tasks in the microtask queue (runAsync()) 445 1. tasks in the microtask queue (scheduleMicrotask())
438 1. tasks in the event queue (new Future() or new Future.delayed()) 446 1. tasks in the event queue (new Future() or new Future.delayed())
439 447
440 Keep in mind that all the calls in the main() function execute synchronously, 448 Keep in mind that all the calls in the main() function execute synchronously,
441 start to finish. 449 start to finish.
442 First main() calls print(), then runAsync(), 450 First main() calls print(), then scheduleMicrotask(),
443 then new Future.delayed(), then new Future(), and so on. 451 then new Future.delayed(), then new Future(), and so on.
444 Only the callbacks—the code in the closure bodies specified as 452 Only the callbacks—the code in the closure bodies specified as
445 arguments to runAsync(), new Future.delayed(), and 453 arguments to scheduleMicrotask(), new Future.delayed(), and
446 new Future()—execute at a later time. 454 new Future()—execute at a later time.
447 455
448 <aside class="alert alert-info" markdown="1"> 456 <aside class="alert alert-info" markdown="1">
449 **Note:** 457 **Note:**
450 Currently, if you comment out the first call to runAsync, 458 Currently, if you comment out the first call to scheduleMicrotask(),
451 then the callbacks for futures #2 and #3 execute before runAsync #2. 459 then the callbacks for futures #2 and #3 execute before microtask #2.
452 This is due to bugs 9001 and 9002, as discussed in 460 This is due to bugs 9001 and 9002, as discussed in
453 [Microtask queue: runAsync()](#microtask-queue-runasync). 461 [Microtask queue: scheduleMicrotask()](#microtask-queue).
454 </aside> 462 </aside>
455 463
456 ### Question #2 464 ### Question #2
457 465
458 Here’s a more complex example. 466 Here’s a more complex example.
459 If you can correctly predict the output of this code, 467 If you can correctly predict the output of this code,
460 you get a gold star. 468 you get a gold star.
461 469
462 {% prettify dart %} 470 {% prettify dart %}
463 import 'dart:async'; 471 import 'dart:async';
464 main() { 472 main() {
465 print('main #1 of 2'); 473 print('main #1 of 2');
466 runAsync(() => print('runAsync #1 of 3')); 474 scheduleMicrotask(() => print('microtask #1 of 3'));
467 475
468 new Future.delayed(new Duration(seconds:1), 476 new Future.delayed(new Duration(seconds:1),
469 () => print('future #1 (delayed)')); 477 () => print('future #1 (delayed)'));
470 478
471 new Future(() => print('future #2 of 4')) 479 new Future(() => print('future #2 of 4'))
472 .then((_) => print('future #2a')) 480 .then((_) => print('future #2a'))
473 .then((_) { 481 .then((_) {
474 print('future #2b'); 482 print('future #2b');
475 runAsync(() => print('runAsync #0 (from future #2b)')); 483 scheduleMicrotask(() => print('microtask #0 (from future #2b)'));
476 }) 484 })
477 .then((_) => print('future #2c')); 485 .then((_) => print('future #2c'));
478 486
479 runAsync(() => print('runAsync #2 of 3')); 487 scheduleMicrotask(() => print('microtask #2 of 3'));
480 488
481 new Future(() => print('future #3 of 4')) 489 new Future(() => print('future #3 of 4'))
482 .then((_) => new Future( 490 .then((_) => new Future(
483 () => print('future #3a (a new future)'))) 491 () => print('future #3a (a new future)')))
484 .then((_) => print('future #3b')); 492 .then((_) => print('future #3b'));
485 493
486 new Future(() => print('future #4 of 4')); 494 new Future(() => print('future #4 of 4'));
487 runAsync(() => print('runAsync #3 of 3')); 495 scheduleMicrotask(() => print('microtask #3 of 3'));
488 print('main #2 of 2'); 496 print('main #2 of 2');
489 } 497 }
490 {% endprettify %} 498 {% endprettify %}
491 499
492 The output, assuming bugs 9001/9002 aren't fixed: 500 The output, assuming bugs 9001/9002 aren't fixed:
493 501
494 <pre> 502 <pre>
495 main #1 of 2 503 main #1 of 2
496 main #2 of 2 504 main #2 of 2
497 runAsync #1 of 3 505 microtask #1 of 3
498 runAsync #2 of 3 506 microtask #2 of 3
499 runAsync #3 of 3 507 microtask #3 of 3
500 future #2 of 4 508 future #2 of 4
501 future #2a 509 future #2a
502 future #2b 510 future #2b
503 future #2c 511 future #2c
504 future #3 of 4 512 future #3 of 4
505 future #4 of 4 513 future #4 of 4
506 runAsync #0 (from future #2b) 514 microtask #0 (from future #2b)
507 future #3a (a new future) 515 future #3a (a new future)
508 future #3b 516 future #3b
509 future #1 (delayed) 517 future #1 (delayed)
510 </pre> 518 </pre>
511 519
512 <aside class="alert alert-info" markdown="1"> 520 <aside class="alert alert-info" markdown="1">
513 **Note:** 521 **Note:**
514 Due to bugs 9001/9002, 522 Due to bugs 9001/9002,
515 runAsync #0 executes after future #4; 523 microtask #0 executes after future #4;
516 it should instead execute before future #3. 524 it should instead execute before future #3.
517 This bug shows up because by the time future #2b executes, 525 This bug shows up because by the time future #2b executes,
518 no runAsync tasks are queued, 526 no microtasks are queued,
519 so runAsync #0 results in a new task on the event queue, 527 so microtask #0 results in a new task on the event queue,
520 which creates a new microtask queue. 528 which creates a new microtask queue.
521 This microtask queue has a task for runAsync #0. 529 This microtask queue contains microtask #0.
522 If you comment out runAsync #1, 530 If you comment out microtask #1,
523 then the runAsync tasks all appear together just after future #2c, 531 then the microtasks all appear together just after future #2c,
524 and before future #3. 532 and before future #3.
525 </aside> 533 </aside>
526 534
527 Like before, the main() function executes, 535 Like before, the main() function executes,
528 and then the tasks on the microtask queue, 536 and then everything on the microtask queue,
529 and then those on the event queue. 537 and then tasks on the event queue.
530 Here are a few interesting points: 538 Here are a few interesting points:
531 539
532 * When the then() callback for future 3 calls new Future(), 540 * When the then() callback for future 3 calls new Future(),
533 it creates a new task (#3a) that’s added to the end of the event queue. 541 it creates a new task (#3a) that’s added to the end of the event queue.
534 * All the then() callbacks execute as soon as 542 * All the then() callbacks execute as soon as
535 the Future they’re invoked on completes. 543 the Future they’re invoked on completes.
536 Thus, future 2, 2a, 2b, and 2c execute all in one go, 544 Thus, future 2, 2a, 2b, and 2c execute all in one go,
537 before control returns to the embedder. 545 before control returns to the embedder.
538 Similarly, future 3a and 3b execute all in one go. 546 Similarly, future 3a and 3b execute all in one go.
539 * If you change the 3a code from 547 * If you change the 3a code from
540 `then((_) => new Future(...))` to 548 `then((_) => new Future(...))` to
541 `then((_) {new Future(...); })`, 549 `then((_) {new Future(...); })`,
542 then "future #3b" appears earlier 550 then "future #3b" appears earlier
543 (after future #3, instead of future #3a). 551 (after future #3, instead of future #3a).
544 The reason is that returning a Future from your callback 552 The reason is that returning a Future from your callback
545 is how you get then() (which itself returns a new Future) 553 is how you get then() (which itself returns a new Future)
546 to _chain_ those two Futures together, 554 to _chain_ those two Futures together,
547 so that the Future returned by then() completes 555 so that the Future returned by then() completes
548 when the Future returned by the callback completes. 556 when the Future returned by the callback completes.
549 See the [then() reference](http://api.dartlang.org/docs/releases/latest/dart_asy nc/Future.html#then) 557 See the [then() reference](http://api.dartlang.org/docs/releases/latest/dart_asy nc/Future.html#then)
550 for more information. 558 for more information.
551 559
552 560
553 #### Annotated sample and output 561 #### Annotated sample and output
554 562
555 Here are some figures that might clarify the answer to question #2. 563 Here are some figures that might clarify the answer to question #2.
556 First, here’s the annotated program source: 564 First, here’s the annotated program source:
557 565
558 ![runAsync lines (which add a microtask) are gold; new Future lines (which sched ule an event) are blue](images/test-annotated.png) 566 ![Lines that schedule a microtask are gold; lines that schedule an event are blu e](images/test-annotated.png)
559 567
560 And here’s what the queues and output look like at various points in time, 568 And here’s what the queues and output look like at various points in time,
561 assuming no external events come in: 569 assuming no external events come in:
562 570
563 ![3 columns: Time, Output, Queues](images/test-queue-output.png) 571 ![3 columns: Time, Output, Queues](images/test-queue-output.png)
564 572
565 573
566 ## Summary 574 ## Summary
567 575
568 You should now understand Dart’s event loops and how to schedule tasks. 576 You should now understand Dart’s event loops and how to schedule tasks.
(...skipping 24 matching lines...) Expand all
593 avoid compute-intensive tasks on either event loop. 601 avoid compute-intensive tasks on either event loop.
594 * To perform compute-intensive tasks, 602 * To perform compute-intensive tasks,
595 create additional isolates or workers. 603 create additional isolates or workers.
596 604
597 As you write asynchronous code, you might find these resources helpful: 605 As you write asynchronous code, you might find these resources helpful:
598 606
599 * [Using Future Based APIs](/articles/using-future-based-apis/) 607 * [Using Future Based APIs](/articles/using-future-based-apis/)
600 * [Futures and Error Handling](/articles/futures-and-error-handling/) 608 * [Futures and Error Handling](/articles/futures-and-error-handling/)
601 * [dart:async - Asynchronous Programming](/docs/dart-up-and-running/contents/ch0 3.html#ch03-asynchronous-programming) section of the library tour 609 * [dart:async - Asynchronous Programming](/docs/dart-up-and-running/contents/ch0 3.html#ch03-asynchronous-programming) section of the library tour
602 * [dart:async API reference](http://api.dartlang.org/dart_async.html) 610 * [dart:async API reference](http://api.dartlang.org/dart_async.html)
OLDNEW
« no previous file with comments | « src/site/articles/event-loop/images/test-queue-output.png ('k') | src/site/articles/futures-and-error-handling/index.markdown » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698