Очередь событий дротика и микрозадача

Я пытаюсь понять, как работает цикл событий дартс. Я прочитал статью о цикле событий с веб-сайта The Event Loop and Dart, и автор довольно хорошо объясняет, как работает цикл обработки событий в dart.

Но что я не понимаю, так это то, как событие попадает в очередь. Например

new Future(() => 21)
    .then((v) => v*2)
    .then((v) => print(v));

Будет ли здесь Дарт создать три записи в очереди событий или только одну? Я знаю, что класс Future отвечает за задержку выполнения и когда я создаю объект из него, как

new Future(() => 21)

это будет только одна запись в цикле событий.

В этой статье, о которой я упоминал выше, я читал о микротаске. Эта микрозадача будет выполняться перед очередью событий, но я не вижу никакого смысла, почему команда dart реализует эту микрозадачу? Может быть, мне нужен пример!

4 ответа

Решение

После некоторого расследования выясняется, что правильный ответ - "они будут выполнены в следующем цикле событий"

Чтобы проверить это, вы можете написать что-то вроде этого:

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");
  });
}

он должен вывести:

в цикле событий
в цикле событий
в цикле событий
до цикла 1
до цикла 2
до цикла 3

Хотя я не уверен, что вы не можете сломать эту оптимизацию. Так что единственно верным фактом является то, что первыйFuture завершит первый, а второй - второй.

РЕДАКТИРОВАТЬ: странная часть (устарела):

С таким кодом:

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");
  });
}

вывод:

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
...

Но с этим:

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");
  });
}

вывод:

в цикле событий
в цикле событий
в цикле событий
до цикла 1
до цикла 2
до цикла 3

EDIT2:

Я думаю, что понял. Во первых (неправильная версия) scheduleMicrotask на самом деле никогда не планировалось должным образом, но, поскольку у Дарта есть активное выполнение аргументов, он выполняет print() тем не мение. Так что же происходит, что все Future выполняется в следующем цикле событий и печатать весь текст. Вот почему вывод в порядке вызова:

до цикла 1
в цикле событий
до цикла 2
в цикле событий
до цикла 3
в цикле событий

а не в порядке расписания.

Когда вы делаете:

new Future(() => 21)
.then((v) => v*2)
.then(print);
  • Сначала вы называете new Future(...) конструктор. Это создает объект Future и планирует таймер для выполнения функции, которую вы задаете в качестве аргумента.
  • Тогда вы звоните then, Это создает новое будущее (назовите это future#2) и добавляет слушателя в первое будущее. Нет запланированных событий.
  • Тогда вы звоните then снова. Это создает еще одно будущее (будущее № 3) и добавляет слушателя на будущее № 2. Нет запланированных событий.
  • Затем срабатывает таймер, и ()=>21 выполняется, и первое будущее завершается со значением 21.
  • Слушатель первого будущего исполняется немедленно. Что вызывает (v)=>c*2 с 21, а затем завершает будущее # 2 со значением 42.
  • Слушатель в будущем # 2 будет немедленно выполнен. Что вызывает print с 42, который печатает 42 и возвращает null, Это завершает будущее № 3 со значением null,

Завершение в будущем в настоящее время осуществляется через функцию "распространения", которая пытается завершить как можно больше фьючерсов, пока их слушатели синхронны. Вот почему завершение одного будущего немедленно завершит другое, без каких-либо промежуточных микрозадач.

Очередь микрозадач состоит в том, чтобы ставить в очередь асинхронное выполнение, но избегать возврата к главному циклу событий до завершения этих микрозадач. Вы можете гарантировать, что некоторые связанные действия будут выполнены полностью, даже если асинхронное выполнение выполнено до выполнения других асинхронных задач / событий, поставленных в очередь в главной очереди.

Кажется, код выполняется из then лайк (v) => v*2 снова выполняется внутри Future так как then всегда возвращает Future,

с https://www.dartlang.org/articles/event-loop/

Очередь для микрозадачи необходима, потому что коду обработки событий иногда требуется выполнить задачу позже, но перед возвратом управления в цикл обработки событий. Например, когда наблюдаемый объект изменяется, он группирует несколько изменений мутаций и сообщает о них асинхронно. Очередь микрозадач позволяет наблюдаемому объекту сообщать об этих изменениях мутации, прежде чем DOM сможет показать несогласованное состояние.

То, как я интерпретирую это описание, не согласуется с результатами тестов в ответе @Jare.

Просто небольшая вещь, чтобы добавить к предыдущим ответам. Статья 'Event Loop' объясняет это поведение довольно хорошо:

Функция, которую вы передаете методу then() в Future, выполняется сразу после завершения Future. (Функция не ставится в очередь, она просто вызывается.)

( https://www.dartlang.org/articles/event-loop/)

Это означает, что в приведенных выше примерах всегда есть одно событие, но много микрозадач.

Другие вопросы по тегам