2017-01-17 2 views
3

У меня есть кусок кода:Понимание генератора JavaScript в

function * input(){ 
    let array = []; 
    while(true) { 
     array.push(yield array); 
    } 
} 

var gen = input(); 
console.log(gen.next("A")) 
console.log(gen.next("B")) 
console.log(gen.next("C")) 
console.log(gen.next("D")) 

Когда вы запустите ее, вы получите следующий результат:

{ value: [], done: false } 
{ value: [ 'B' ], done: false } 
{ value: [ 'B', 'C' ], done: false } 
{ value: [ 'B', 'C', 'D' ], done: false } 

Почему первая строка результата не включает A в массиве? Существует одно объяснение с этой страницы: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*#Passing_arguments_into_Generators. Комментарий говорит

первый вызов следующего() не выполняется с самого начала функции до первого оператора выхода

Но из моего тестирования, кажется, не правильно. Мой код тестирования:

function* logGenerator() { 
    console.log("before yield in function"); 
    yield 1; 
    console.log("filler 1"); 
    yield 2; 
    console.log("filler 2"); 
    yield 3; 
    console.log("filler 3"); 
} 

var gen = logGenerator(); 

console.log(gen.next()); 
console.log("-----------------"); 
console.log(gen.next()); 
console.log("-----------------"); 
console.log(gen.next()); 
console.log("-----------------"); 
console.log(gen.next()); 

Результат:

before yield in function 
{ value: 1, done: false } 
----------------- 
filler 1 
{ value: 2, done: false } 
----------------- 
filler 2 
{ value: 3, done: false } 
----------------- 
filler 3 
{ value: undefined, done: true } 

Как вы можете видеть, первый next() не только выполнил заявления перед первым yield, но и первый yield заявление. Так что теория не может объяснить мой вопрос. Может ли кто-нибудь помочь мне указать правильное направление? Заранее спасибо.

+1

Оператор доходности должен иметь преимущество. –

+1

Это интересно. running 'console.log (gen.next());' сначала дает ожидаемый результат –

ответ

1

Рассмотрите первый генератор, который вы написали, переписан таким образом.

function * input(){ 
 
    let array = []; 
 
    while(true) { 
 
     var thingToAdd = yield array; 
 
     console.log(thingToAdd); 
 
     array.push(thingToAdd); 
 
    } 
 
} 
 

 
var gen = input(); 
 
console.log(gen.next("A")) 
 
console.log(gen.next("B")) 
 
console.log(gen.next("C")) 
 
console.log(gen.next("D"))

Разве не ясно понять, почему «А» никогда не добавляется в массив? Первое выполнение генератора останавливается в первом операторе вывода задолго до того, как массив когда-либо будет изменен. К тому моменту, когда выполнение возвращается к генератору, переданное значение имеет значение «B». Такая же динамика происходит в вашем коде здесь array.push(yield array); Сначала вычисляются внутренние выражения, поэтому yield останавливает выполнение до того, как будет получен доступ к push.

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

Также, прочитав раздел «Отправить», this article иллюстрирует вашу ситуацию.

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

var q1 = gen.next(); 
console.log(q1); 
var a = userInput(); 
var q2 = gen.next(a); 
console.log(q2); 
var a2 = userInput(); 
... 
0
function * foo() { 
    var i = 0 
    yield i 

    i += 1 
    yield i 

    i += 1 
    i += 2 
    yield i 
} 

var gen = foo() 
console.log(gen.next()) // 0 
console.log(gen.next()) // 1 
console.log(gen.next()) // 4 

Обратите внимание, что var gen = foo() просто создает экземпляр генератора. Это первый вызов .next(), который запускает выполнение генератора. Генераторы выполняются до тех пор, пока они не достигнут yield statement и вернут значение этого yield заявление. В этот момент генератор приостанавливается до тех пор, пока не будет выполнен другой вызов .next().

Итак, все работает в соответствии с вашими примерами. В первом примере первый оператор yield возвращает пустой массив. В следующем .next() массив заполняется значением, переданным в, и тогда этот массив будет получен. В коде:

function * foo (param) { 
    var array = [] 
    // do nothing with param 
    yield array 

    array.push(param) // 'B' 
    yield array 

    array.push(param) // 'C' 
    yield array 

    array.push(param) // 'D' 
    yield array 
} 

Это соответствует the documentation:

Если дополнительное значение передается метода генератора следующей(), то значение становится значением, возвращаемого текущей операцией выхода генератора.

Смежные вопросы