นักพัฒนา 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