นักพัฒนา JavaScript สร้าง Pipeline Operator ที่ใช้งานได้จริงด้วยเทคนิค Symbol.toPrimitive Hack

ทีมชุมชน BigGo
นักพัฒนา JavaScript สร้าง Pipeline Operator ที่ใช้งานได้จริงด้วยเทคนิค Symbol.toPrimitive Hack

นักพัฒนา JavaScript ได้ค้นพบวิธีการอันชาญฉลาดในการนำการเขียนโปรแกรมแบบ pipeline มาใช้ในภาษานี้ได้ในปัจจุบัน โดยไม่ต้องรอการสนับสนุนไวยากรณ์อย่างเป็นทางการ ไลบรารี asPipes ใช้วิธีการแก้ปัญหาอย่างสร้างสรรค์ด้วยฟีเจอร์ที่มีอยู่ใน JavaScript เพื่อจำลอง pipeline operator ที่รอคอยมานานซึ่งติดอยู่ในขั้นตอนการเสนอมาหลายปี

ข้อเสนอ pipeline operator ได้รับการหารือที่ TC39 มาหลายปีแล้ว โดยสำรวจแนวทางที่แตกต่างกันเช่น F# และ Hack variants ในขณะที่ชุมชน JavaScript รอการสนับสนุนอย่างเป็นทางการ นักพัฒนาก็เริ่มรู้สึกหงุดหงิดกับความคืบหน้าที่ช้า

การใช้ Symbol.toPrimitive อย่างสร้างสรรค์

ไลบรารีทำงานโดยการแฮ็กระบบการแปลงประเภทของ JavaScript เมื่อคุณใช้ตัวดำเนินการ bitwise OR (|>) JavaScript จะพยายามแปลงออบเจ็กต์เป็นค่าพื้นฐาน ไลบรารี asPipes ขัดขวางกระบวนการแปลงนี้โดยใช้ Symbol.toPrimitive ทำให้สามารถจับและเชื่อมต่อการดำเนินการแทนที่จะทำการดำเนินการ bitwise จริงๆ

แนวทางนี้ช่วยให้นักพัฒนาเขียนโค้ดที่ดูคล้ายกับไวยากรณ์ pipeline ที่เสนออย่างน่าทึ่ง คุณสามารถเชื่อมต่อการแปลงต่างๆ เข้าด้วยกันในรูปแบบที่อ่านได้ง่าย ไหลจากซ้ายไปขวาที่รู้สึกเป็นธรรมชาติ และไม่จำเป็นต้องใช้การเรียกฟังก์ชันแบบซ้อนหรือตัวแปรชั่วคราว

สมาชิกในชุมชนได้สังเกตรายละเอียดทางเทคนิคที่น่าสนใจเกี่ยวกับแนวทางนี้ ไลบรารีไม่ได้ตรวจสอบพารามิเตอร์ conversion hint ที่ JavaScript ให้มาจริงๆ ซึ่งหมายความว่าอาจทำงานผิดปกติในบริบทบางอย่างเช่น string templates

เป้าหมายการออกแบบ

  • สามารถชดเชยได้: การแปลงแต่ละครั้งทำหน้าที่เป็นฟังก์ชันเอกภาค
  • การดำเนินการแบบเลื่อน: ไม่มีการดำเนินการจนกว่าจะเรียก run()
  • ปลอดภัยสำหรับ Async: รองรับ promises และ async functions อย่างเต็มรูปแบบ
  • ไร้สถานะ: ไม่มีการเปลี่ยนแปลงส่วนกลาง มีบริบท pipeline ที่แยกออกจากกัน
  • ใช้งานง่าย: การจัดเรียงภาพที่สอดคล้องกับไวยากรณ์ของตัวดำเนินการ |> ในอนาคต

ปรัชญาการออกแบบที่เน้น Async เป็นหลัก

ฟีเจอร์ที่โดดเด่นอย่างหนึ่งคือวิธีที่ไลบรารีจัดการกับการดำเนินการแบบอะซิงโครนัส ไม่เหมือนยูทิลิตี้ JavaScript หลายๆ ตัวที่มองว่า async เป็นเรื่องรอง asPipes ทำให้ promises และ async functions ทำงานได้อย่างราบรื่นภายใน pipelines แต่ละขั้นตอนสามารถคืนค่าปกติหรือ promise ก็ได้ และไลบรารีจัดการความซับซ้อนเบื้องหลัง

โมเดลการดำเนินการแบบเลื่อนหมายความว่าไม่มีอะไรทำงานจริงๆ จนกว่าคุณจะเรียกเมธอด run() สิ่งนี้ให้การควบคุมที่ละเอียดเกี่ยวกับเวลาที่การคำนวณเกิดขึ้น และทำให้ง่ายขึ้นในการสร้างคอมโพเนนต์ pipeline ที่ใช้ซ้ำได้

Async functions คือฟังก์ชันที่สามารถหยุดชั่วคราวและรอให้การดำเนินการอื่นๆ เสร็จสิ้น ซึ่งใช้กันทั่วไปสำหรับการร้องขอเครือข่ายหรือการดำเนินการไฟล์

ฟังก์ชัน API หลัก

  • createAsPipes(): สร้างสภาพแวดล้อม pipeline แบบแยกตัว
  • pipe(initialValue): เริ่มต้น pipeline ใหม่ด้วยค่าเริ่มต้น
  • asPipe(func): ห่อหุ้มฟังก์ชันให้เข้ากันได้กับ pipeline
  • run(): ประเมินผล pipeline และคืนค่า Promise ของผลลัพธ์สุดท้าย

ความสามารถในการประมวลผล Stream

ไลบรารีขยายไปเกินกว่าการแปลงค่าง่ายๆ เพื่อรองรับการประมวลผล stream ด้วย async generators สิ่งนี้เปิดโอกาสสำหรับรูปแบบการเขียนโปรแกรมเชิงฟังก์ชันแบบ reactive เช่น การประมวลผลเหตุการณ์เมาส์หรือการจัดการ data streams แบบเรียลไทม์

โมดูล streams ให้เครื่องมือการเขียนโปรแกรมเชิงฟังก์ชันที่คุ้นเคยเช่น map, filter และ reduce ที่ทำงานกับทั้งอาร์เรย์ปกติและ async data streams สิ่งนี้ทำให้เป็นไปได้ที่จะสร้าง data processing pipelines ที่ซับซ้อนซึ่งสามารถจัดการทุกอย่างตั้งแต่การแปลงง่ายๆ ไปจนถึงการประมวลผลเหตุการณ์แบบเรียลไทม์

ฟังก์ชันการประมวลผลสตรีม

  • map(iterable, fn): แปลงแต่ละรายการในสตรีม
  • filter(iterable, predicate): กรองรายการตามเงื่อนไข
  • take(iterable, n): นำรายการ n รายการแรกจากสตรีม
  • scan(iterable, reducer, initial): สะสมผลลัพธ์พร้อมแสดงผลระหว่างกลาง
  • reduce(iterable, reducer, initial): ลดสตรีมให้เหลือค่าเดียว

ข้อจำกัดทางเทคนิคและการแลกเปลี่ยน

แม้จะเป็นนวัตกรรม แต่แนวทางนี้มาพร้อมกับข้อจำกัดสำคัญบางประการ ด้านขวาของ pipeline สามารถใช้ได้เฉพาะฟังก์ชัน pipeable ที่ห่อหุ้มพิเศษเท่านั้น ไม่ใช่นิพจน์ใดๆ ก็ได้ นี่หมายความว่าคุณไม่สามารถใส่โค้ด JavaScript ใดๆ ลงไปได้ - ทุกอย่างต้องเตรียมไว้สำหรับการใช้งาน pipeline

การใช้งานมากเกินไปอาจทำให้เครื่องมือหรือ linters สับสน

ลักษณะ hack ของโซลูชันนี้ยังหมายความว่าเครื่องมือพัฒนาอาจไม่เข้าใจสิ่งที่เกิดขึ้น ซึ่งอาจนำไปสู่ข้อความแสดงข้อผิดพลาดที่สับสนหรือการเน้นไวยากรณ์ที่ไม่ถูกต้อง

ผู้สร้างไลบรารีซื่อสัตย์เกี่ยวกับข้อจำกัดเหล่านี้และวางตำแหน่งสิ่งนี้เป็นการสาธิตมากกว่าโซลูชันที่พร้อมสำหรับการใช้งานจริง มันทำหน้าที่เป็นการพิสูจน์แนวคิดว่า pipeline semantics สามารถทำงานใน JavaScript ได้อย่างไร และให้วิธีสำหรับนักพัฒนาในการทดลองกับรูปแบบการเขียนโปรแกรมในปัจจุบัน

การทดลอง asPipes แสดงให้เห็นว่านักพัฒนา JavaScript สามารถสร้างสรรค์ได้อย่างไรเมื่อต้องแก้ไขข้อจำกัดของภาษา แม้ว่าจะยังไม่พร้อมสำหรับการใช้งานจริง แต่ก็ให้ข้อมูลเชิงลึกที่มีค่าเกี่ยวกับวิธีที่ pipeline operators อาจทำงานในทางปฏิบัติ และช่วยให้การสนทนาดำเนินต่อไปในขณะที่ข้อเสนออย่างเป็นทางการยังคงหยุดนิ่ง

อ้างอิง: asPipes: working pipelines today in pure JavaScript