Skip to main content

เนื้อหาภาษาไทย / Thai content

System guide Content reviewed

Generators

บทความนี้แนะนำ Generators ใน JavaScript ซึ่งเป็นฟังก์ชันพิเศษที่ใช้สร้าง iterators ได้อย่างง่ายดาย โดยใช้ `function*` และ keyword `yield` เพื่อหยุดและกลับมาทำงา...

Generators: สร้าง Iterators อย่างง่ายดายด้วย JavaScript

ในบทความก่อนหน้า เราได้สำรวจ Reflect API ซึ่งเป็นเครื่องมืออันทรงพลังสำหรับการทำงานกับ Object ใน JavaScript อย่างปลอดภัยและมีประสิทธิภาพ ในบทความนี้ เราจะมาเรียนรู้เกี่ยวกับ Generators ซึ่งเป็นฟีเจอร์ที่ช่วยให้เราสร้าง iterators ได้อย่างง่ายดายและยืดหยุ่น โดยเฉพาะอย่างยิ่งเมื่อต้องการสร้างลำดับข้อมูลที่ซับซ้อนหรืออนันต์

Generators คืออะไร?

Generators คือฟังก์ชันพิเศษชนิดหนึ่งใน JavaScript ที่สามารถหยุดการทำงานชั่วคราว (pause) และกลับมาทำงานต่อ (resume) ได้ในภายหลัง ซึ่งแตกต่างจากฟังก์ชันทั่วไปที่เมื่อเริ่มทำงานแล้วจะทำงานจนเสร็จสิ้น Generator จะคืนค่าเป็น Iterator Object ซึ่งสามารถใช้เพื่อดึงข้อมูลทีละรายการจากลำดับข้อมูลที่สร้างขึ้น

การสร้าง Generator Function ด้วย function*

ในการสร้าง Generator Function เราจะใช้ syntax function* แทนที่ function ปกติ ตัวอย่าง:

function* myGenerator() {
  yield 1;
  yield 2;
  yield 3;
}

const iterator = myGenerator();

console.log(iterator.next()); // { value: 1, done: false }
console.log(iterator.next()); // { value: 2, done: false }
console.log(iterator.next()); // { value: 3, done: false }
console.log(iterator.next()); // { value: undefined, done: true }

ในตัวอย่างนี้ myGenerator เป็น Generator Function เมื่อเราเรียกใช้ myGenerator() มันจะไม่ทำงานทันที แต่จะคืนค่าเป็น Iterator Object ที่ชื่อ iterator เราสามารถใช้ method next() ของ iterator เพื่อดึงค่าทีละรายการจาก Generator Function

เมื่อเรียก iterator.next() ครั้งแรก Generator Function จะทำงานจนกระทั่งพบ keyword yield ซึ่งจะหยุดการทำงานชั่วคราวและคืนค่าที่อยู่หลัง yield (ในที่นี้คือ 1) พร้อมกับ property done: false ซึ่งบ่งบอกว่ายังไม่สิ้นสุดการทำงาน

เมื่อเรียก iterator.next() ครั้งต่อๆ ไป Generator Function จะกลับมาทำงานต่อจากจุดที่หยุดไว้ครั้งก่อน จนกระทั่งพบ yield ตัวถัดไป หรือจนกว่าจะสิ้นสุดการทำงานของฟังก์ชัน เมื่อสิ้นสุดการทำงานของฟังก์ชัน next() จะคืนค่า undefined พร้อมกับ property done: true

Keyword yield

yield เป็น keyword สำคัญใน Generator Function มันทำหน้าที่:

  • หยุดการทำงานของ Generator Function ชั่วคราว
  • คืนค่าที่อยู่หลัง yield ให้กับ Iterator Object
  • อนุญาตให้ Generator Function กลับมาทำงานต่อจากจุดที่หยุดไว้

นอกจากนี้ yield ยังสามารถรับค่าจากภายนอกได้ด้วย โดยการส่งค่าเข้าไปใน next() method ค่าที่ส่งเข้าไปจะถูกกำหนดให้กับตัวแปรที่อยู่ทางซ้ายของ yield ตัวอย่าง:

function* myGenerator() {
  const value = yield 'รอรับค่า...';
  console.log('ค่าที่ได้รับ:', value);
  yield value * 2;
}

const iterator = myGenerator();

console.log(iterator.next()); // { value: 'รอรับค่า...', done: false }
console.log(iterator.next(5)); // ค่าที่ได้รับ: 5, { value: 10, done: false }
console.log(iterator.next()); // { value: undefined, done: true }

ในตัวอย่างนี้ เมื่อเรียก iterator.next() ครั้งแรก Generator Function จะหยุดการทำงานที่ yield 'รอรับค่า...' และคืนค่า 'รอรับค่า...' เมื่อเรียก iterator.next(5) ค่า 5 จะถูกส่งเข้าไปใน Generator Function และกำหนดให้กับตัวแปร value จากนั้น Generator Function จะทำงานต่อและแสดงผลลัพธ์ ค่าที่ได้รับ: 5 และหยุดการทำงานอีกครั้งที่ yield value * 2 โดยคืนค่า 10

การสร้าง Infinite Sequence ด้วย Generators

หนึ่งในประโยชน์ที่สำคัญของ Generators คือความสามารถในการสร้าง Infinite Sequence หรือลำดับข้อมูลที่ไม่มีวันสิ้นสุด ตัวอย่าง:

function* infiniteSequence() {
  let count = 0;
  while (true) {
    yield count++;
  }
}

const sequence = infiniteSequence();

console.log(sequence.next().value); // 0
console.log(sequence.next().value); // 1
console.log(sequence.next().value); // 2
// ... และต่อไปเรื่อยๆ

ในตัวอย่างนี้ infiniteSequence เป็น Generator Function ที่สร้างลำดับตัวเลขที่เพิ่มขึ้นเรื่อยๆ อย่างไม่มีที่สิ้นสุด เนื่องจาก while (true) จะทำงานตลอดไป Generator Function จะไม่สิ้นสุดการทำงานเอง แต่เราสามารถควบคุมการดึงข้อมูลจากลำดับได้โดยการเรียก sequence.next() ตามจำนวนครั้งที่เราต้องการ

ข้อควรระวัง: การสร้าง Infinite Sequence ต้องระมัดระวังในการใช้งาน เนื่องจากหากไม่มีการควบคุมการดึงข้อมูล อาจทำให้โปรแกรมทำงานหนักเกินไปหรือค้างได้

กรณีใช้งานจริงของ Generators

Generators มีประโยชน์ในหลายสถานการณ์ เช่น:

  • Data Streaming: อ่านและประมวลผลข้อมูลทีละส่วนจากไฟล์ขนาดใหญ่ หรือจาก API ที่ส่งข้อมูลมาเป็น stream
  • Asynchronous Programming: จัดการ Asynchronous Operations อย่างง่ายดาย โดยใช้ yield เพื่อรอผลลัพธ์จาก Promise หรือ Asynchronous Function
  • State Management: สร้าง State Machines ที่ซับซ้อนได้อย่างง่ายดาย
  • Custom Iterators: สร้าง Iterators สำหรับ data structures ที่ไม่มี Iterator ในตัว

ตัวอย่างการใช้งาน: Data Streaming

function* readLines(file) {
  // สมมติว่า 'file' เป็น object ที่มี method 'readLine'
  // ซึ่งอ่านข้อมูลจากไฟล์ทีละบรรทัด
  while (!file.eof()) {
    yield file.readLine();
  }
}

// สมมติว่า 'myFile' เป็น instance ของ File object
const lines = readLines(myFile);

for (const line of lines) {
  console.log(line);
}

ในตัวอย่างนี้ readLines เป็น Generator Function ที่อ่านข้อมูลจากไฟล์ทีละบรรทัด เมื่อ yield file.readLine() ถูกเรียกใช้ Generator Function จะหยุดการทำงานชั่วคราวและคืนข้อมูลที่อ่านได้ เมื่อมีการวนซ้ำด้วย for...of Generator Function จะกลับมาทำงานต่อและอ่านข้อมูลบรรทัดถัดไป ทำเช่นนี้ไปเรื่อยๆ จนกว่าจะถึงจุดสิ้นสุดของไฟล์

ข้อผิดพลาดที่พบบ่อยในการใช้งาน Generators

  • ลืมเรียก next(): หากไม่เรียก next() Iterator Object จะไม่ทำงานและไม่มีการดึงข้อมูล
  • การใช้งาน yield นอก Generator Function: yield สามารถใช้ได้เฉพาะภายใน Generator Function เท่านั้น
  • การสร้าง Infinite Loop ที่ไม่มีทางออก: ระวังการสร้าง Infinite Sequence ที่ไม่มีการควบคุมการดึงข้อมูล
  • การจัดการ Error: ควรจัดการ Error ภายใน Generator Function เพื่อป้องกันไม่ให้โปรแกรมหยุดทำงาน

สรุป

Generators เป็นเครื่องมือที่มีประโยชน์ในการสร้าง Iterators อย่างง่ายดายและยืดหยุ่น โดยเฉพาะอย่างยิ่งเมื่อต้องการสร้างลำดับข้อมูลที่ซับซ้อนหรืออนันต์ การทำความเข้าใจ function* และ yield เป็นสิ่งสำคัญในการใช้งาน Generators อย่างมีประสิทธิภาพ ในบทความถัดไป เราจะมาเรียนรู้เกี่ยวกับ Iterators and Iterables ซึ่งเป็น concepts ที่เกี่ยวข้องกับ Generators และช่วยให้เราทำงานกับข้อมูลได้อย่างมีประสิทธิภาพมากยิ่งขึ้น

Office.in.th Custom Service

Want to build or adapt a system from this structure?

Office.in.th designs and develops enterprise web applications, API integrations, and public- and private-sector management systems, with long-term support.

See our software development service