Подтвердить что ты не робот

Что такое генераторы ES6 и как их использовать в node.js?

Сегодня я был на встрече node.js, и кто-то, кого я там встречал, сказал, что node.js имеет генераторы es6. Он сказал, что это огромное улучшение по сравнению с программированием стиля обратного вызова, и изменит ландшафт node. Айц, он сказал что-то о стеке вызовов и исключениях.

Я просмотрел их, но на самом деле не нашел никакого ресурса, который объясняет их в удобном для новичков. Каков общий обзор генераторов высокого уровня и как отличаются (или лучше?), Чем обратные вызовы?

PS: Было бы очень полезно, если бы вы могли дать фрагмент кода, чтобы подчеркнуть разницу в общих сценариях (создание HTTP-запроса или вызов db).

4b9b3361

Ответ 1

Генераторы, волокна и сопрограммы

"Генераторы" (помимо "генераторов" ) также являются основными блоками зданий "fiber" или "coroutines" . С помощью волокон вы можете "приостановить" функцию, ожидающую возвращения асинхронного вызова, эффективно избегая объявления функции обратного вызова "на месте" и создания "закрытия". Попрощайтесь с адским обратным вызовом.

Закрытие и попытка

... он сказал что-то о стеке вызовов и исключениях

Проблема с "закрытием" заключается в том, что даже если они "магически" сохраняют состояние локальных переменных для обратного вызова, "закрытие" не может содержать стек вызовов.

В момент обратного вызова, как правило, вызывающая функция вернулась давным-давно, поэтому любой блок "catch" вызывающей функции не может перехватывать исключения в самой функции async или обратном вызове. Это представляет большую проблему. Из-за этого вы не можете комбинировать обратные вызовы + замыкания с исключением catching.

Wait.for

... и изменит ландшафт node

Если вы используете генераторы для создания вспомогательной библиотеки типа Wait.for-ES6 (я автор), вы можете полностью избежать обратного вызова и закрытия, и теперь "блоки блокировки" работают, как ожидалось, и код прост.

Было бы очень полезно, если бы вы могли дать фрагмент кода, чтобы подчеркнуть разницу в общих сценариях (создание HTTP-запроса или вызов db).

Проверьте Wait.for-ES6 примеры, чтобы увидеть тот же код с обратными вызовами и с волокнами на основе генераторов.

Ответ 2

Генераторы являются одним из многих функций в предстоящем ES6. Таким образом, в будущем их можно будет использовать в браузерах (прямо сейчас вы можете играть с ними в FF).

Генераторы являются конструкторами для итераторов. Похоже на тарабарщину, поэтому в упрощенных выражениях они позволяют создавать объекты, которые позже можно будет перебирать с помощью чего-то вроде циклов с использованием метода .next().

Генераторы определяются аналогично функциям. Кроме того, в них есть * и yield. * означает, что это генератор, выход аналогичен возврату.

Например, это генератор:

function *seq(){
    var n = 0;
    while (true) yield n++;
}

Затем вы можете использовать этот генератор с var s = seq(). Но в отличие от функции он не выполнит все и не даст вам результата, он просто создаст генератор. Только когда вы запустите s.next(), генератор будет выполнен. Здесь доходность аналогична возврату, но когда выход будет работать, он остановит генератор и продолжит работу над следующим выражением после следующего. Но когда будет вызываться следующий s.next(), генератор возобновит выполнение. В этом случае он будет продолжать делать цикл while навсегда.

Итак, вы можете повторить это с помощью

for (var i = 0; i < 5; i++){
  console.log( s.next().value )
}

или с конкретной конструкцией для генераторов:

for (var n of seq()){
    if (n >=5) break;
    console.log(n);
}

Это основы генераторов (вы можете посмотреть yield*, next(with_params), throw() и другие дополнительные конструкции). Обратите внимание, что речь идет о генераторах в ES6 (так что вы можете сделать все это в node и в браузере).

Но как эта бесконечная последовательность чисел имеет какое-либо отношение к обратному вызову?

Важная вещь здесь заключается в том, что выход приостанавливает генератор. Итак, представьте, что у вас очень странная система, которая работает таким образом:

У вас есть база данных с пользователями, и вам нужно найти имя пользователя с некоторым идентификатором, тогда вам нужно проверить в своей файловой системе ключ для этого имени пользователя, а затем вам нужно подключиться к некоторым ftp с идентификатором пользователя и ключ и сделать что-то после подключения. (Звучит смешно, но я хочу показать вложенные обратные вызовы).

Раньше вы писали бы что-то вроде этого:

var ID = 1;
database.find({user : ID}, function(userInfo){
    fileSystem.find(userInfo.name, function(key){
        ftp.connect(ID, key, function(o){
            console.log('Finally '+o);
        })
    })
});

Это обратный вызов внутри обратного вызова внутри обратного вызова внутри обратного вызова. Теперь вы можете написать что-то вроде:

function *logic(ID){
  var userInfo  = yield database.find({user : ID});
  var key       = yield fileSystem.find(userInfo.name);
  var o         = yield ftp.connect(ID, key);
  console.log('Finally '+o);
}
var s = logic(1);

И затем используйте его with s.next(); Как вы видите, нет вложенных обратных вызовов.

Поскольку node сильно использует вложенные обратные вызовы, вот почему парень говорил, что генераторы могут изменять ландшафт node.

Ответ 3

Генератор представляет собой комбинацию двух вещей - a Iterator и a Observer.

Итератор

Итератор - это то, что при вызове возвращает итерабельность, которую вы можете повторить. Начиная с ES6, все коллекции (Array, Map, Set, WeakMap, WeakSet) соответствуют контракту Iterable.

Генератор (итератор) является производителем. В итерации потребитель PULL получает значение от производителя.

Пример:

function *gen() { yield 5; yield 6; }
let a = gen();

Всякий раз, когда вы вызываете a.next(), вы по существу PULL -интегрируете значение из Iterator и pause исполнение в yield. При следующем вызове a.next() выполнение возобновляется из ранее приостановленного состояния.

Observer

Генератор также является наблюдателем, с помощью которого вы можете отправить некоторые значения обратно в генератор. Объясняется лучше с примерами.

function *gen() {
  document.write('<br>observer:', yield 1);
}
var a = gen();
var i = a.next();
while(!i.done) {
  document.write('<br>iterator:', i.value);
  i = a.next(100);
}

Ответ 4

Чтобы использовать генераторы ES6 в node, вам нужно либо установить node >= 0.11.2, либо iojs.

В node вам нужно будет указать флаг гармонии:

$ node --harmony app.js 

или вы можете явно ссылаться на флаг генераторов

$ node --harmony_generators app.js

Если вы установили iojs, вы можете опустить флаг гармонии.

$ iojs app.js

Для получения обзора высокого уровня о том, как использовать генераторы, проверить этот пост.