Колкото и да искам да си припиша заслугите за тази публикация, тя е написана предимно от Джон Пипкин. Беше наистина добро и ми помогна много и исках да бъде споделено със света.

„Щракнете тук за цялата му статия“

Така че тествайки генераторите, най-добре е да мислите за тях като за цикли, които се изпълняват, когато им кажете.

Етап 1

it(‘should return 6’, () => {
 // we’ve set up the generator, but we haven’t called next yet so we’re not at a yield
 const gen = count()
expect(gen.next().value).toEqual(call(addNumber, number, 1))
expect(gen.next(1).value).toEqual(call(addNumber, number, 2))
expect(gen.next(3).value).toEqual(call(addNumber, number, 3))
expect(gen.next(6).value).toEqual(put(something(6)))
})
function *count() {
 -> // We haven’t told the generator to exicute anything yet so we’re not at a yield
 let number = 0
number = yield call(addNumber, number, 1)
 number = yield call(addNumber, number, 2) //3
 number = yield call(addNumber, number, 3) //6
 yield.put(something(number))
}

В тази стъпка все още не сме казали на генератора да направи нещо, така че нямаме какво да тестваме.

Стъпка 2

it(‘should return 6’, () => {
 const gen = count()
// This next is called, we’re seeing what the yield will be
 expect(gen.next().value).toEqual(call(addNumber, number, 1))
expect(gen.next(1).value).toEqual(call(addNumber, number,2))
expect(gen.next(3).value).toEqual(call(addNumber, number, 3))
expect(gen.next(6).value).toEqual(put(something(6)))
})
function *count() {
 let number = 0
// Generator is paused here, waiting. The yield call(addNumber, number, 1) hasn’t executed
 -> number = yield call(addNumber, number, 1)
 number = yield call(addNumber, number, 2) //3
 number = yield call(addNumber, number, 3) //6
 yield.put(something(number))
}

Тук изпълнихме gen.next(). Казахме на генератора да премине към изявлението за доходност и да изчака. Така че сега сме на пауза при ->, но всъщност не сме изпълнили кода.

Когато получим gen.next().value тук, ние просто получаваме какво ЩЕ направи добивът.

Стъпка 3

it(‘should return 6’, () => {
 const gen = count()
expect(gen.next().value).toEqual(call(addNumber, number, 1))
// called next here, this evaluated the previous line. We pass in the return value from the last line
 expect(gen.next(1).value).toEqual(call(addNumber, number, 2))
expect(gen.next(3).value).toEqual(call(addNumber, number, 3))
expect(gen.next(6).value).toEqual(put(something(6)))
})
function *count() {
 let number = 0
number = yield call(addNumber, number, 1)
 // We evaluated the previous line, now were waiting at the this yield
 -> number = yield call(addNumber, number, 2) 
 number = yield call(addNumber, number, 3) //6
 yield.put(something(number))
}

Тук извикахме отново gen.next(). Генераторът вижда тази команда и изпълнява yield-а, на който е била поставена на пауза, и продължава следващия оператор `yield`. Ще спре тук ->. gen.next() казва на оператора yield, в който е трябвало да се изпълни, можем да предадем това, което искаме да бъде върнато от това, в повикването
Бяхме поставени на пауза при yield call(addNumber, number, 1), искахме това да се върне 1, така че предаваме това, когато всъщност изпълняваме този ред .

Стъпка 4

it(‘should return 6’, () => {
 const gen = count()
expect(gen.next().value).toEqual(call(addNumber, number,1))
expect(gen.next(1).value).toEqual(call(addNumber, number, 2))
// Called next again, we evaluated the call to (number, 2) and specifiy its return value in this next
 expect(gen.next(3).value).toEqual(call(addNumber, number, 3))
expect(gen.next(6).value).toEqual(put(something(6)))
})
function *count() {
 let number = 0
number = yield call(addNumber, number, 1)
 number = yield call(addNumber, number, 2) //3
 -> number = yield call(addNumber, number,3) //6
 yield.put(something(number))
}

Тази е точно като предишната стъпка, само за да илюстрирам това, за което говоря. Добивът на call(addNumber, number, 2) трябва да върне 3, така че ние го предаваме на извикването на gen.next(3), защото сме казали на генератора да изпълни този ред и искаме той да върне 3.

Стъпка 5

it(‘should return 6’, () => {
 const gen = count()
expect(gen.next().value).toEqual(call(addNumber, number, 1))
expect(gen.next(1).value).toEqual(call(addNumber, number, 2))
expect(gen.next(3).value).toEqual(call(addNumber, number, 3))
// Called next again, we evaluated the call to (number, 3) and specifiy its return value in this next.
 // I’ve intentionally returned the wrong value from the call to (addNumber, number, 3) to illustrate how the return in next works
 expect(gen.next(8).value).toEqual(put(something(8)))
})
function *count() {
 let number = 0
number = yield call(addNumber, number, 1)
 number = yield call(addNumber, number, 2) //3
 number = yield call(addNumber, number, 3) //6
 -> yield.put(something(number))
}

Извикахме отново gen.next(), така че сега чакаме доходността за пут. В този пример можете да видите, че умишлено върнах грешна стойност `8` в gen.next(). Това е, за да илюстрира, че next приема върнатата стойност от предишното изпълнение. По същество фалшиви данни в този случай. Сега виждаме, че доходността, на която сме поставили на пауза, е put(number). Тъй като number в този случай е 8 (тъй като това казахме на call(addNumber, number, 3) да се върне, това е, което търсим.

Стъпка 6

it(‘should return 6’, () => {
 const gen = count()
expect(gen.next().value).toEqual(call(addNumber, number, 1))
expect(gen.next(1).value).toEqual(call(addNumber, number, 2))
expect(gen.next(3).value).toEqual(call(addNumber, number, 3))
expect(gen.next(8).value).toEqual(put(something(8)))
// Finally call next again to see there are no more yields
 expect(gen.next().done).toBeTruthy()
})
function *count() {
 let number = 0
number = yield call(addNumber, number, 1)
 number = yield call(addNumber, number, 2) //3
 number = yield call(addNumber, number, 3) //6
 yield.put(something(number))
 ->
}

Накрая се обаждаме отново на gen.next(). Тъй като няма повече добиви, които да чакаме, можем да видим, че сагата е приключила.