问题
i am trying to understand, how dart event loop works. I read the event loop article from the website The Event Loop and Dart and the author explain pretty good how event loop in dart works.
But what i don't understand is, how event get queue. For example
new Future(() => 21)
.then((v) => v*2)
.then((v) => print(v));
Will here dart gonna create three entries in the event queue or just one? I know, that the class Future is responsible for delay execution and when i create an object from it like
new Future(() => 21)
it will be just one entry in the event loop.
In this article, that i have mentioned above, i read about microtask. This microtask is going to execute before event queue, but i don't see any sense, why dart team implement this microtask? Maybe i need some example!
回答1:
After some investigation it appears that the right answer is "they will be executed in the next event loop"
To test it you can write something like this:
import "dart:async";
void main() {
new Future(() {
scheduleMicrotask(()=>print("before loop 1"));
print("in event loop");
}).then((_) {
scheduleMicrotask(()=>print("before loop 2"));
print("in event loop");
}).then((_) {
scheduleMicrotask(()=>print("before loop 3"));
print("in event loop");
});
}
it should output:
in event loop
in event loop
in event loop
before loop 1
before loop 2
before loop 3
Although i'm not sure that you can't break this optimization. So only sure fact is that the firstFuture
will complete first and the second - second.
EDIT: The strange part(Obsolete):
With code like this:
import "dart:async";
void main() {
new Future(() {
scheduleMicrotask(print("before loop 1"));
print("in event loop");
}).then((_) {
scheduleMicrotask(print("before loop 2"));
print("in event loop");
}).then((_) {
scheduleMicrotask(print("before loop 3"));
print("in event loop");
});
}
output is:
before loop 1
in event loop
before loop 2
in event loop
before loop 3
in event loop
Unhandled exception:
The null object does not have a method 'call'.
NoSuchMethodError: method not found: 'call'
Receiver: null
...
But with this:
import "dart:async";
void main() {
new Future(() {
scheduleMicrotask(()=>print("before loop 1"));
print("in event loop");
}).then((_) {
scheduleMicrotask(()=>print("before loop 2"));
print("in event loop");
}).then((_) {
scheduleMicrotask(()=>print("before loop 3"));
print("in event loop");
});
}
output is:
in event loop
in event loop
in event loop
before loop 1
before loop 2
before loop 3
EDIT2:
I think i got it. In the first(wrong version) scheduleMicrotask
actually never got properly scheduled, but since Dart has eager argument execution it executes print()
anyway. So what happens is that all Future
getting executed in the next event loop and print all text.
That's why output is in call order:
before loop 1
in event loop
before loop 2
in event loop
before loop 3
in event loop
and not in the schedule order.
回答2:
When you do:
new Future(() => 21)
.then((v) => v*2)
.then(print);
- First you call the
new Future(...)
constructor. This creates a Future object and schedules a Timer to execute the function you give as argument. - Then you call
then
. This creates a new future (call it future#2) and adds a listener on the first future. No events are scheduled. - Then you call
then
again. This creates yet another future (future#3) and adds a listener on the future#2. No events are scheduled. - Then the timer triggers, and the
()=>21
is executed, and the first future is completed with the value 21. - The listener on the first future is then executed immediately. That calls
(v)=>v*2
with 21, and then completes future#2 with the value 42. - The listener on future#2 is then executed immediately. That calls
print
with 42, which prints 42 and returnsnull
. This completes future#3 with the valuenull
.
Future completion is currently done through a "propagate" function that tries to complete as many futures as possible, as long as their listeners are synchronous. That is why completing one future will immediately complete another, without any intermediate microtasks.
回答3:
The microtask queue is to queue async execution but avoid returning to the main event loop before these microtasks are finished. You can ensure some related activities to be completed entirely even when executed async before other async tasks/events queued in the main queue are executed.
It seems the code executed from then
like (v) => v*2
is again executed inside a Future
because then
always returns a Future
.
from https://www.dartlang.org/articles/event-loop/
The microtask queue is necessary because event-handling code sometimes needs to complete a task later, but before returning control to the event loop. For example, when an observable object changes, it groups several mutation changes together and reports them asychronously. The microtask queue allows the observable object to report these mutation changes before the DOM can show the inconsistent state.
How I interpret this description doesn't fit with the results in the tests in @Jare 's answer.
回答4:
Just a little thing to add to previous answers. The 'Event Loop' article explains this behavior pretty well:
The function that you pass into Future’s then() method executes immediately when the Future completes. (The function isn’t enqueued, it’s just called.)
(https://www.dartlang.org/articles/event-loop/)
It means that in above examples there's always one event but many microtasks.
来源:https://stackoverflow.com/questions/24030271/dart-event-queue-and-microtask