Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> JavaScript

Từ khóa yield trong JavaScript: Generator Functions

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

  1. Gọi generator function → trả về Generator Object (iterator), KHÔNG chạy code body ngay.
  2. Gọi generator.next() → chạy đến yield đầu tiên, tạm dừng, trả về { value: ..., done: false }.
  3. Gọi next() lại → tiếp tục từ sau yield, chạy đến yield tiếp theo.
  4. 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 ý

  • yield chỉ dùng trong function* (SyntaxError nếu dùng ngoài).
  • Generator là Iterable – dùng được for...of, spread, Array.from().
  • return trong generator set done: true, yield set done: false.
  • Error handling: gen.throw(error) ném error vào generator tại yield hiện tại.