2017-02-17 23 views
9
function* foo() { 
    yield 123 
}; 

// - - - 

function* foo() { 
    return yield 123 
}; 

Я не могу продемонстрировать разницу между ними.Генераторы JS: Как `return yield` отличается от` yield`?

  • Есть ли очевидная разница?
  • Следует ли использовать return в генераторе?
+0

спасибо, что спросили, многие ответы помогут мне узнать больше о генераторах JS. – yussan

ответ

10

Во-первых, я начну с того, что генераторы представляют собой довольно сложную тему, поэтому полный обзор здесь невозможен. Для получения дополнительной информации я настоятельно рекомендую Kyle Simpson's You Don't Know JS. Книга 5 (Async & Performance) имеет прекрасную дискуссию о входе и выходе генераторов.

На конкретном примере, который вы дали, хотя!

Во-первых, код, который вы написали в примере покажет никакой разницы но только если это правильно работать. Вот пример:

function* foo() { 
    yield 123; 
} 

function* bar() { 
    return yield 123; 
} 

var f = foo(); 
var b = bar(); 

f.next(); // {value: 123, done: false} 
f.next(); // {value: undefined, done: true} 
b.next(); // {value: 123, done: false} 
b.next(); // {value: undefined, done: true} 

Как вы можете видеть, я не называю генератор нормальной функцией. Сам генератор возвращает объект генератора (форма итератора). Мы сохраняем этот итератор в переменной и используем функцию .next(), чтобы переместить итератор на следующий шаг (ключевое слово yield10 или return).

Ключевое слово yield позволяет нам передавать значение в генератор, и здесь ваши примеры будут работать по-разному. Вот что это будет выглядеть следующим образом:

function* foo() { 
    yield 123; 
} 

function* bar() { 
    return yield 123; 
} 

var f = foo(); 
var b = bar(); 

// Start the generator and advance to the first `yield` 
f.next(); // {value: 123, done: false} 
b.next(); // {value: 123, done: false} 

/** Now that I'm at a `yield` statement I can pass a value into the `yield` 
* keyword. There aren't any more `yield` statements in either function, 
* so .next() will look for a return statement or return undefined if one 
* doesn't exist. Like so: 
*/ 
f.next(2); // {value: undefined, done: true} 
b.next(2); // {value: 2, done: true} 

Обратите внимание, что foo() возвратит undefined как значение, в то время как bar() возвращает номер 2. Это происходит потому, что значение мы передаем в .next() вызов отправляется на return ключевое слово и установить в качестве возвращаемого значения. foo() не имеет явного оператора return, поэтому вы получаете поведение по умолчанию undefined.

Надеюсь, что это поможет!

6

Разница является результатом значение последнего продолжения вызова:

function* fooA() { 
    yield 123 
}; 
var a = fooA(); 
console.log(a.next(1)); // {done:false, value:123} 
console.log(a.next(2)); // {done:true, value:undefined} 

function* fooB() { 
    return 40 + (yield 123) 
}; 
var b = fooB(); 
console.log(b.next(1)); // {done:false, value:123} 
console.log(b.next(2)); // {done:true, value:42} 

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

Однако существуют также генераторы, в которых важно значение результата, например. когда они используются в качестве инструмента для описания асинхронных процессов (в полифонии для async/await синтаксиса обещания, а также многих других вещей, таких как CSP). Вы также получаете значение return при использовании yield* на истребителе.

В любом случае, return yield вместе звучит не очень полезно.