Попытка понять генераторы/выход в node.js - что выполняет асинхронная функция?

Node.js теперь имеет генераторы.

Мое понимание заключается в том, что генераторы могут использоваться для написания кода, который выглядит намного более линейным и позволяет избежать обратного вызова ада и пирамиды кодирования стиля doom.

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

Возвращаемая функция возврата возвращается к тому, что называется генератором.

Мой вопрос: что происходит в этот момент? Что именно выполняет функция блокирующего ввода-вывода, возвращаемая доходностью?

Правильно ли, что для записи кода генератора/выхода, который кажется линейным, должна существовать определенная функция, которая вызывает генератор, функцию, которая проходит через генератор и выполняет каждую асинхронную функцию, возвращаемую выходом и возвращает результат асинхронной функции обратно в генератор?

Мне все еще не ясно, как выполняется функция asynch, возвращаемая выходом. Если он выполняется функцией, вызывающей генератор, выполняется ли она асинхронно? Я угадываю, потому что иначе это приведет к блокированию поведения.

Обобщение моих вопросов:

  • Для написания "линейного" асинхронного кода с генераторами необходимо, чтобы там была вызывающая функция, которая выполняет итерацию по генератору, выполняя заданные функции как обратные вызовы и возвращая результат обратного вызова обратно в генератор?
  • Если ответ на вопрос 1 да, то точно как выполняются выполняемые функции - асинхронно?

Может ли кто-нибудь предложить лучший обзор/резюме того, как работает весь процесс?

Ответы

Ответ 1

При написании асинхронного кода с генераторами вы имеете дело с двумя типами функций:

  • нормальные функции, объявленные с помощью function. Эти функции не могут уступить. Вы не можете писать асинхронный код в стиле синхронизации с ними, потому что они выполняются до завершения; вы можете обрабатывать только асинхронное завершение через обратные вызовы (если вы не вызываете дополнительную мощность, например, библиотеку node-fibers или преобразование кода).
  • функции генератора, объявленные с помощью function*. Эти функции могут дать. Вы можете написать асинхронный код в стиле синхронизации внутри них, потому что они могут дать. Но вам нужна вспомогательная функция, которая создает генератор, обрабатывает обратные вызовы и возобновляет генератор при вызове next каждый раз, когда срабатывает обратный вызов.

Существует несколько библиотек, которые реализуют функции компаньона. В большинстве этих библиотек функция companion обрабатывает один function* за раз, и вы должны поместить обертку вокруг каждого function* в свой код. Библиотека галактики (которую я написал) немного особенна, потому что она может обрабатывать function* вызов другого function* без промежуточных оберток. Сопутствующая функция немного сложна, потому что она имеет дело со стеком генераторов.

Поток выполнения может быть трудно понять из-за небольшого танца yield/next между вашим function* и функцией компаньона. Один из способов понять поток - написать пример с выбранной вами библиотекой, добавить операторы console.log как в свой код, так и в библиотеку и запустить его.

Ответ 2

Если [блокирующая функция io] выполняется функцией, вызывающей генератор, выполняется ли он асинхронно? Я так думаю, потому что в противном случае это приведет к блокированию поведения.

Я не думаю, что генераторы выполняют асинхронную обработку задач. С генераторами одновременно выполняется только одно - просто одна функция может прекратить выполнение и передать управление другой функции. Например,

function iofunc1() {
  console.log('iofunc1');
}

function iofunc2() {
  console.log('iofunc2');
}

function* do_stuff() {
  yield iofunc1;
  yield iofunc2;
  console.log('goodbye');
}


var gen = do_stuff();
(gen.next().value)(); 
(gen.next().value)(); //This line won't begin execution until the function call on the previous line returns
gen.next(); //continue executing do_stuff

Если вы прочитали некоторые статьи об генераторах nodejs:

... все они используют дополнительные функции/библиотеки для добавления в асинхронное выполнение.

Ответ 3

1: написать "линейный" асинхронный код с генераторами, необходимо ли там должна быть функция вызова, которая выполняет итерацию по генератору, выполнение заданных функций в качестве обратных вызовов и возврат результата обратный вызов обратно в генератор?

Да. Позвольте называть его "пусковой установкой".

2: если ответ на вопрос 1 да, то точно как выполняемые функции - асинхронно?

Внутри генератора вы получаете массив с: функцией и ее параметрами. В управляющем вызывающем устройстве (пусковой установке) вы используете функцию fn.apply(.., callback) для вызова async, помещая вызов в "generator.next(data)"; (резюме) внутри обратного вызова.

асинхронная функция выполняется асинхронно, но генератор будет "приостановлен" в пределе текучести, пока не будет вызван обратный вызов (а затем выполняется "generator.next(data)" )

Полная рабочая библиотека и образцы: https://github.com/luciotato/waitfor-es6