JavaScript Generators Tutorial - Section 1: Introduction
function* myGenerator() {
yield 1;
yield 2;
yield 3;
}
const gen = myGenerator();
console.log(gen.next()); // { value: 1, done: false }
const myGenerator = function* () {
yield 'a';
yield 'b';
yield 'c';
};
const gen = myGenerator();
console.log([...gen]); // ['a', 'b', 'c']
const obj = {
*myGenerator() {
yield 1;
yield 2;
},
// Alternative syntax
myGenerator2: function* () {
yield 3;
yield 4;
}
};
console.log([...obj.myGenerator()]); // [1, 2]
console.log([...obj.myGenerator2()]); // [3, 4]
class MyClass {
*instanceGenerator() {
yield 'instance';
}
static *staticGenerator() {
yield 'static';
}
}
const instance = new MyClass();
console.log([...instance.instanceGenerator()]); // ['instance']
console.log([...MyClass.staticGenerator()]); // ['static']
function* basicYield() {
yield 1;
yield 2;
yield 3;
}
const gen = basicYield();
console.log(gen.next().value); // 1
console.log(gen.next().value); // 2
console.log(gen.next().value); // 3
function* yieldExpressions() {
yield 1 + 1;
yield Math.random();
yield 'Hello' + ' ' + 'World';
yield [1, 2, 3];
yield { name: 'John', age: 30 };
}
for (const value of yieldExpressions()) {
console.log(value);
}
// 2
// 0.123... (random)
// Hello World
// [1, 2, 3]
// { name: 'John', age: 30 }
function* conditionalYield(n) {
for (let i = 0; i < n; i++) {
if (i % 2 === 0) {
yield i;
}
}
}
console.log([...conditionalYield(10)]); // [0, 2, 4, 6, 8]
function* executionFlow() {
console.log('Start');
yield 1;
console.log('After first yield');
yield 2;
console.log('After second yield');
yield 3;
console.log('After third yield');
return 'Done';
}
const gen = executionFlow();
console.log('Created generator');
console.log(gen.next()); // Logs: Start, Returns: { value: 1, done: false }
console.log(gen.next()); // Logs: After first yield, Returns: { value: 2, done: false }
console.log(gen.next()); // Logs: After second yield, Returns: { value: 3, done: false }
console.log(gen.next()); // Logs: After third yield, Returns: { value: 'Done', done: true }
function* withReturn() {
yield 1;
yield 2;
return 3; // Final value
yield 4; // Never reached
}
const gen = withReturn();
console.log(gen.next()); // { value: 1, done: false }
console.log(gen.next()); // { value: 2, done: false }
console.log(gen.next()); // { value: 3, done: true }
console.log(gen.next()); // { value: undefined, done: true }
// Note: for...of doesn't include return value
console.log([...withReturn()]); // [1, 2]
function* range(start, end, step = 1) {
for (let i = start; i <= end; i += step) {
yield i;
}
}
console.log([...range(1, 10)]); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
console.log([...range(0, 20, 5)]); // [0, 5, 10, 15, 20]
function* repeat(value, times) {
for (let i = 0; i < times; i++) {
yield value;
}
}
console.log([...repeat('hello', 3)]); // ['hello', 'hello', 'hello']
console.log([...repeat(0, 5)]); // [0, 0, 0, 0, 0]
function* cycle(array) {
while (true) {
for (const item of array) {
yield item;
}
}
}
const colors = cycle(['red', 'green', 'blue']);
console.log(colors.next().value); // red
console.log(colors.next().value); // green
console.log(colors.next().value); // blue
console.log(colors.next().value); // red (cycles back)
function* filter(iterable, predicate) {
for (const item of iterable) {
if (predicate(item)) {
yield item;
}
}
}
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const evens = filter(numbers, n => n % 2 === 0);
console.log([...evens]); // [2, 4, 6, 8, 10]
function* map(iterable, transform) {
for (const item of iterable) {
yield transform(item);
}
}
const numbers = [1, 2, 3, 4, 5];
const doubled = map(numbers, n => n * 2);
console.log([...doubled]); // [2, 4, 6, 8, 10]
function* numbers() {
yield 1;
yield 2;
yield 3;
}
function* letters() {
yield 'a';
yield 'b';
yield 'c';
}
function* combined() {
yield* numbers();
yield* letters();
}
console.log([...combined()]); // [1, 2, 3, 'a', 'b', 'c']
function* idGenerator(prefix = 'ID') {
let id = 1;
while (true) {
yield `${prefix}-${String(id).padStart(5, '0')}`;
id++;
}
}
const userIds = idGenerator('USER');
console.log(userIds.next().value); // USER-00001
console.log(userIds.next().value); // USER-00002
console.log(userIds.next().value); // USER-00003
const orderIds = idGenerator('ORDER');
console.log(orderIds.next().value); // ORDER-00001
console.log(orderIds.next().value); // ORDER-00002
function* paginate(items, pageSize) {
for (let i = 0; i < items.length; i += pageSize) {
yield items.slice(i, i + pageSize);
}
}
const data = Array.from({ length: 25 }, (_, i) => i + 1);
const pages = paginate(data, 10);
console.log(pages.next().value); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
console.log(pages.next().value); // [11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
console.log(pages.next().value); // [21, 22, 23, 24, 25]
function* statefulGenerator() {
let state = 0;
while (true) {
const input = yield state;
if (input === 'increment') {
state++;
} else if (input === 'decrement') {
state--;
} else if (input === 'reset') {
state = 0;
}
}
}
const gen = statefulGenerator();
console.log(gen.next().value); // 0
console.log(gen.next('increment').value); // 1
console.log(gen.next('increment').value); // 2
console.log(gen.next('decrement').value); // 1
console.log(gen.next('reset').value); // 0
function* syntaxyield pauses execution and returns valuesreturn ends generator (value not in iteration)Now that you understand basic syntax, let's explore yield expressions in depth!