yield là từ khóa dùng chỉ trong Generator Function (function*) để tạm dừng thực thi và trả về giá trị cho caller, sau đó có thể tiếp tục từ chỗ đã dừng.
Cú pháp Generator Function
// 3 cách khai báo đều hợp lệ
function *gen1() {}
function* gen2() {}
function*gen3() {}
// Arrow function KHÔNG hỗ trợ generator
// const gen = () => { yield 1; } // SyntaxError
Cơ chế hoạt động
- Gọi generator function → trả về Generator Object (iterator), KHÔNG chạy code body ngay.
- Gọi
generator.next()→ chạy đếnyieldđầu tiên, tạm dừng, trả về{ value: ..., done: false }. - Gọi
next()lại → tiếp tục từ sauyield, chạy đếnyieldtiếp theo. - Khi hàm kết thúc (return hoặc hết code) → trả về
{ value: returnValue, done: true }.
Ví dụ cơ bản
function* numberGenerator() {
yield 1;
yield 2;
yield 3;
return "Done";
}
const gen = numberGenerator(); // Không chạy code nào
console.log(gen.next()); // { value: 1, done: false }
console.log(gen.next()); // { value: 2, done: false }
console.log(gen.next()); // { value: 3, done: false }
console.log(gen.next()); // { value: "Done", done: true }
console.log(gen.next()); // { value: undefined, done: true }
Ví dụ từ bài gốc (đã sửa lỗi: i → a)
function* displayRank() {
const selPlayers = [1, 2, 3, 4];
for (let a = 0; a < selPlayers.length; a++) {
yield selPlayers[a]; // Sửa selPlayers[i] → selPlayers[a]
}
}
const rank = displayRank();
console.log(rank.next().value); // 1
console.log(rank.next().value); // 2
console.log(rank.next().value); // 3
console.log(rank.next().value); // 4
console.log(rank.next().value); // undefined (done: true)
Yield với giá trị đầu vào (Two-way communication)
function* logger() {
console.log("Start");
const input1 = yield "First yield"; // Tạm dừng, trả "First yield"
console.log("Received:", input1); // Nhận giá trị từ next(input1)
const input2 = yield "Second yield";
console.log("Received:", input2);
return "Finished";
}
const gen = logger();
console.log(gen.next()); // { value: "First yield", done: false }
console.log(gen.next("Hello")); // { value: "Second yield", done: false } - log: "Received: Hello"
console.log(gen.next("World")); // { value: "Finished", done: true } - log: "Received: World"
Yield* – Delegation (Delegating yield)
function* inner() {
yield 1;
yield 2;
}
function* outer() {
yield 0;
yield* inner(); // Delegating to inner generator
yield 3;
}
[...outer()]; // [0, 1, 2, 3]
Ứng dụng thực tế
- Lazy evaluation / Infinite sequences: Fibonacci, prime numbers, ID generator.
- Async flow control: Kết hợp với Promise (co library, redux-saga).
- Iterable data structures: Tree traversal, pagination.
- State machines: Modeling complex state transitions.
// Infinite Fibonacci generator
function* fibonacci() {
let [a, b] = [0, 1];
while (true) {
yield a;
[a, b] = [b, a + b];
}
}
const fib = fibonacci();
fib.next().value; // 0
fib.next().value; // 1
fib.next().value; // 1
fib.next().value; // 2
fib.next().value; // 3
fib.next().value; // 5
// ... vô hạn, không bị stack overflow
Lưu ý
yieldchỉ dùng trongfunction*(SyntaxError nếu dùng ngoài).- Generator là Iterable – dùng được
for...of,spread,Array.from(). returntrong generator setdone: true,yieldsetdone: false.- Error handling:
gen.throw(error)ném error vào generator tại yield hiện tại.