Колкото и да искам да си припиша заслугите за тази публикация, тя е написана предимно от Джон Пипкин. Беше наистина добро и ми помогна много и исках да бъде споделено със света.
„Щракнете тук за цялата му статия“
Така че тествайки генераторите, най-добре е да мислите за тях като за цикли, които се изпълняват, когато им кажете.
Етап 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()
. Тъй като няма повече добиви, които да чакаме, можем да видим, че сагата е приключила.