jsrosetta

Hàm

Generator

Generator function và iterator helpers của Node.js so với Iterator (Rust), AsyncStream (Swift), virtual thread (Java) và `iter.Seq`/channel trong Go.

Phiên bản tối thiểu
Node.js ≥ 22Go ≥ 1.23Rust ≥ 1.58Swift ≥ 5.7Java ≥ 25
Đã chạy thử trên
Node.js 24.12.0Go 1.27.1Rust 1.98.1Swift 6.2.4Java 25.0.4.1

Code Node.js là ES module: lưu file .mjs hoặc đặt "type": "module" trong package.json.

Node.js có generator function (function* / yield) built-in: gọi hàm không chạy gì cả, mỗi lần gọi .next() mới chạy tới yield tiếp theo. Không ngôn ngữ nào khác trong danh sách có yield thật. Rust không cần giả lập gì nhiều: Iterator vốn đã "pull" từng giá trị một qua .next(), nên std::iter::from_fn — một closure giữ state và trả Option<T> — gần như là generator viết tay. Swift dùng AsyncStream, thứ duy nhất trong 5 ngôn ngữ có một API tên đúng là yield() — nhưng khác với from_fn của Rust vốn lazy (chỉ chạy khi bị gọi .next()), closure của AsyncStream chạy eager ngay khi được tạo và đệm (buffer) sẵn các giá trị yield ra. Java không có gì dựng sẵn, nhưng từ bản 21 có virtual thread: chạy phần thân generator trên một virtual thread và đồng bộ qua SynchronousQueue để mô phỏng yield chặn (blocking). Go không có cú pháp generator, nhưng từ 1.23 có iter.Seq — kiểu "range-over-func" giúp bạn range trực tiếp qua một hàm giống hệt range qua slice hay map. Trước đó (và vẫn còn hợp lệ), cách kinh điển là dùng channel.

Định nghĩa generator

function* generator() {
  yield 'hello';
  yield 'world';
}

Lấy giá trị thủ công (next() / done)

const gen = generator();
 
while (true) {
  const { value, done } = gen.next();
  console.log(value, done);
 
  if (done) {
    break;
  }
}
// hello false
// world false
// undefined true

Duyệt bằng for...of / iterator helpers

for (const value of generator()) {
  console.log(value);
}
// hello
// world
 
// generator object cũng là iterator, nên iterator helpers biến đổi được
// trực tiếp, không cần spread ra mảng trước
for (const value of generator().map((word) => word.toUpperCase())) {
  console.log(value);
}
// HELLO
// WORLD

Channel vẫn là một cách hợp lệ để mô hình hoá generator giữa các goroutine — nó có từ trước Go 1.23 và không bị iter.Seq thay thế hoàn toàn. Go cũng không có chuỗi iterator helper dựng sẵn (.map(), .filter(), …); bạn phải biến đổi giá trị ngay trong vòng lặp. Rust và Swift có: Iterator/AsyncSequence đều có .map() dựng sẵn từ lâu. Java thì giống Go — Iterator trần không có .map(), phải đổi sang Stream trước.

Tham khảo: github.com/miguelmota/golang-for-nodejs-developers#generators