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

เจฟฟ์ พอสนิก
เจฟฟ์ พอสนิก

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

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

เมื่อเขียนเครื่องจัดการเหตุการณ์ fetch ของคุณเอง เป็นเรื่องปกติที่จะส่งผ่าน respondWith() เมธอด Response (หรือคำมั่นสัญญาสำหรับ Response) ที่คุณได้รับผ่าน fetch() หรือ caches.match() และเรียกใช้เพียงวันเดียว ข่าวดีคือคุณสตรีม 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() และจะอ่านสตรีมนั้นต่อไปเรื่อยๆ ตราบใดที่โปรแกรมทำงานของบริการยังคงenqueue()รับข้อมูลเพิ่มเติม การตอบสนองที่ไหลจาก Service Worker ไปยังหน้าไม่พร้อมกันอย่างแท้จริง และเราสามารถควบคุมการเติมเต็มสตรีมได้อย่างเต็มที่

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

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

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

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

สตรีม หรือ App Shell

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

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

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

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

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

เจาะลึกสตรีม

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

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

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

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

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

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