สตรีมคำตอบได้ทันที

ทุกคนที่เคยใช้ Service Worker จะบอกได้ว่าการทำงานเป็นแบบแอซิงโครนัสตั้งแต่ต้นจนจบ โดยอาศัยอินเทอร์เฟซแบบเหตุการณ์เท่านั้น เช่น FetchEvent และใช้ Promise เพื่อส่งสัญญาณเมื่อการดำเนินการแบบไม่พร้อมกันเสร็จสมบูรณ์

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

เมื่อเขียนตัวแฮนเดิลเหตุการณ์ fetch ของคุณเอง โดยทั่วไปแล้วคุณเพียงแค่ส่ง Response (หรือสัญญาสำหรับ Response) ที่คุณได้รับผ่าน fetch() หรือ caches.match() ไปยังเมธอด respondWith() แล้วจบ ข่าวดีคือ Response ที่สร้างขึ้นด้วยทั้ง 2 วิธีดังกล่าวสามารถสตรีมได้แล้ว ข่าวร้ายคือResponseที่สร้าง "ด้วยตนเอง" จะสตรีมไม่ได้ อย่างน้อยก็จนถึงตอนนี้ ด้วยเหตุนี้ Streams API จึงเข้ามามีบทบาท

สตรีม

สตรีมคือแหล่งข้อมูลที่สร้างและดัดแปลงได้ทีละส่วน รวมถึงมีอินเทอร์เฟซสําหรับการอ่านหรือเขียนข้อมูลแบบไม่พร้อมกัน ซึ่งอาจมีเพียงชุดย่อยเท่านั้นที่พร้อมใช้งานในหน่วยความจํา ณ เวลาหนึ่งๆ ในระหว่างนี้ เราสนใจ ReadableStream ซึ่งสามารถใช้ในการสร้างออบเจ็กต์ Response ที่ส่งไปยัง fetchEvent.respondWith()

self.addEventListener('fetch', event => {
    var stream = new ReadableStream({
    start(controller) {
        if (/* there's more data */) {
        controller.enqueue(/* your data here */);
        } else {
        controller.close();
        }
    });
    });

    var response = new Response(stream, {
    headers: {'content-type': /* your content-type here */}
    });

    event.respondWith(response);
});

หน้าเว็บที่คำขอทริกเกอร์เหตุการณ์ fetch จะได้รับคำตอบแบบสตรีมกลับทันทีที่มีการเรียก event.respondWith() และจะอ่านจากสตรีมนั้นต่อไปตราบใดที่ Service Worker ยังคงenqueue()ข้อมูลเพิ่มเติม การตอบกลับที่ส่งจาก Service Worker ไปยังหน้าเว็บเป็นแบบไม่พร้อมกันอย่างแท้จริง และเราควบคุมการเติมข้อมูลสตรีมได้อย่างสมบูรณ์

การใช้งานจริง

คุณอาจสังเกตเห็นว่าตัวอย่างก่อนหน้านี้มีความคิดเห็นเกี่ยวกับตัวยึดตําแหน่ง /* your data here */ และรายละเอียดการใช้งานจริงไม่มากนัก ตัวอย่างการใช้งานจริงจะเป็นอย่างไร

Jake Archibald (ไม่น่าแปลกใจเลย) มีตัวอย่างที่ยอดเยี่ยมในการใช้สตรีมเพื่อต่อข้อมูลการตอบกลับ HTML จากข้อมูลโค้ด HTML หลายรายการที่แคชไว้เข้าด้วยกัน พร้อมกับข้อมูล "สด" ที่สตรีมผ่าน fetch() ซึ่งในกรณีนี้คือเนื้อหาสำหรับบล็อกของเขา

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

สตรีม หรือเปลือกแอป

แนวทางปฏิบัติแนะนำที่มีอยู่เกี่ยวกับการใช้ Service Worker เพื่อขับเคลื่อนเว็บแอปมุ่งเน้นที่รูปแบบ App Shell + เนื้อหาแบบไดนามิก แนวทางนี้อาศัยการแคช "เชลล์" ของแอปพลิเคชันเว็บอย่างหนักหน่วง ซึ่งก็คือ HTML, JavaScript และ CSS ขั้นต่ำที่จำเป็นในการแสดงโครงสร้างและเลย์เอาต์ จากนั้นจึงโหลดเนื้อหาแบบไดนามิกที่จำเป็นสำหรับแต่ละหน้าผ่านคําขอฝั่งไคลเอ็นต์

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

ข้อได้เปรียบที่สําคัญอย่างหนึ่งของการสตรีมการตอบกลับ HTML ทั้งหมด ซึ่งอธิบายว่าเหตุใดจึงเป็นทางเลือกที่เร็วที่สุดในวิดีโอคือ HTML ที่แสดงผลระหว่างคําขอไปยังส่วนต่างๆ ครั้งแรกสามารถใช้ประโยชน์จากโปรแกรมแยกวิเคราะห์ HTML แบบสตรีมของเบราว์เซอร์ได้อย่างเต็มที่ ข้อมูล HTML ที่แทรกลงในเอกสารหลังจากที่โหลดหน้าเว็บแล้ว (ซึ่งพบได้ทั่วไปในโมเดล App Shell) จะไม่ใช้ประโยชน์จากการเพิ่มประสิทธิภาพนี้

ดังนั้น หากคุณอยู่ในขั้นตอนการวางแผนการติดตั้งใช้งาน Service Worker คุณควรใช้รูปแบบใดระหว่างการตอบสนองแบบสตรีมที่แสดงผลแบบเป็นขั้นๆ หรือเชลล์ที่มีน้ำหนักเบาซึ่งใช้ร่วมกับคำขอฝั่งไคลเอ็นต์สำหรับเนื้อหาแบบไดนามิก คำตอบนั้นขึ้นอยู่กับว่าคุณมีการใช้งานเดิมที่ใช้ CMS และเทมเพลตบางส่วนหรือไม่ (ข้อดี: สตรีม) คุณต้องการเพย์โหลด HTML ขนาดใหญ่รายการเดียวที่จะได้รับประโยชน์จากการเรนเดอร์แบบเป็นขั้นๆ หรือไม่ (ข้อดี: สตรีม) เว็บแอปของคุณควรได้รับการโมเดลเป็นแอปพลิเคชันหน้าเว็บเดียวหรือไม่ (ข้อดี: App Shell) และคุณจำเป็นต้องใช้รูปแบบที่ปัจจุบันได้รับการรองรับในรุ่นที่เสถียรของหลายเบราว์เซอร์หรือไม่ (ข้อดี: App Shell)

เรายังอยู่ในช่วงเริ่มต้นของการใช้การตอบสนองแบบสตรีมมิงที่ทำงานด้วย Service Worker และหวังว่าจะเห็นโมเดลต่างๆ พัฒนาขึ้น และหวังว่าจะเห็นการพัฒนาเครื่องมือเพิ่มเติมเพื่อทำให้ Use Case ทั่วไปทำงานอัตโนมัติ

เจาะลึกเกี่ยวกับสตรีม

หากคุณสร้างสตรีมที่อ่านได้ของคุณเอง การเรียกใช้ controller.enqueue() โดยไม่เลือกหน้าอาจไม่เพียงพอหรือไม่มีประสิทธิภาพ Jake อธิบายอย่างละเอียดเกี่ยวกับวิธีใช้เมธอด start(), pull() และ cancel() ร่วมกันเพื่อสร้างสตรีมข้อมูลที่ปรับให้เหมาะกับกรณีการใช้งานของคุณ

สำหรับผู้ที่ต้องการรายละเอียดเพิ่มเติม ข้อมูลจำเพาะของสตรีมมีข้อมูลให้คุณ

ความเข้ากันได้

รองรับการสร้างออบเจ็กต์ Response ภายใน Service Worker โดยใช้ ReadableStream เป็นแหล่งที่มาใน Chrome 52

การใช้งาน Service Worker ของ Firefox ยังไม่รองรับการตอบกลับที่รองรับ ReadableStream แต่มีข้อบกพร่องการติดตามที่เกี่ยวข้องสําหรับการสนับสนุน Streams API ที่คุณติดตามได้

คุณติดตามความคืบหน้าเกี่ยวกับการรองรับ Streams API ที่ไม่มีคำนำหน้าใน Edge รวมถึงการรองรับ Service Worker โดยรวมได้ที่หน้าสถานะแพลตฟอร์มของ Microsoft