ในโมดูลสุดท้าย เราได้ให้ภาพรวมของ Web Worker ไว้ Web Worker ปรับปรุงการตอบสนองของอินพุตได้โดยย้าย JavaScript ออกจากเทรดหลักไปยังเทรด Web Worker แยกกัน ซึ่งจะช่วยปรับปรุงการโต้ตอบกับ Next Paint (INP) ของเว็บไซต์เมื่อคุณมีงานที่ไม่จำเป็นต้องเข้าถึงเทรดหลักโดยตรง อย่างไรก็ตาม ภาพรวมเพียงอย่างเดียวนั้นยังไม่เพียงพอ และในโมดูลนี้ เราได้นำเสนอกรณีการใช้งานที่เป็นรูปธรรมสำหรับผู้ปฏิบัติงานเว็บ
กรณีการใช้งานหนึ่งอาจเป็นเว็บไซต์ที่ต้องตัดข้อมูลเมตา Exif ออกจากรูปภาพ ซึ่งไม่ใช่แนวคิดที่แก้ปัญหาได้ยาก ที่จริงแล้ว เว็บไซต์อย่าง Flickr นำเสนอวิธีดูข้อมูลเมตา Exif แก่ผู้ใช้เพื่อดูรายละเอียดทางเทคนิคเกี่ยวกับรูปภาพที่โฮสต์ เช่น ความลึกของสี ยี่ห้อและรุ่นของกล้อง และข้อมูลอื่นๆ
อย่างไรก็ตาม ตรรกะในการดึงรูปภาพ การแปลงรูปภาพเป็น ArrayBuffer
และการแยกข้อมูลเมตา Exif อาจมีค่าใช้จ่ายสูงหากดำเนินการทั้งหมดในเทรดหลัก โชคดีที่ขอบเขตของ Web Worker ช่วยให้ทำงานนี้ได้จากเทรดหลัก จากนั้น เมื่อใช้ไปป์ไลน์การรับส่งข้อความของ Web Worker ระบบจะส่งข้อมูลเมตา Exif กลับไปยังเทรดหลักเป็นสตริง HTML และแสดงให้ผู้ใช้เห็น
เทรดหลักมีลักษณะอย่างไรเมื่อไม่มี Web Worker
ก่อนอื่น ให้สังเกตว่าเทรดหลักมีลักษณะอย่างไรเมื่อเราทำงานนี้โดยไม่ต้องใช้ Web Worker โดยทำตามขั้นตอนต่อไปนี้
- เปิดแท็บใหม่ใน Chrome และเปิดเครื่องมือสำหรับนักพัฒนาเว็บ
- เปิดแผงประสิทธิภาพ
- ไปที่ https://exif-worker.glitch.me/without-worker.html
- ในแผงประสิทธิภาพ ให้คลิกบันทึกที่มุมขวาบนของแผงเครื่องมือสำหรับนักพัฒนาเว็บ
- วางลิงก์รูปภาพนี้ หรือลิงก์อื่นที่คุณเลือกที่มีข้อมูลเมตา Exif ลงในช่องแล้วคลิกปุ่มรับ JPEG นั้น
- เมื่ออินเทอร์เฟซเติมข้อมูลด้วยข้อมูลเมตา Exif แล้ว ให้คลิกบันทึกอีกครั้งเพื่อหยุดการบันทึก
โปรดทราบว่าทุกอย่างในแอปเกิดขึ้นในเทรดหลัก นอกเหนือจากชุดข้อความอื่นๆ ที่อาจมีอยู่ เช่น ชุดข้อความแรสเตอร์และอื่นๆ สิ่งต่อไปนี้จะเกิดขึ้นในเทรดหลัก
- แบบฟอร์มจะรับอินพุตและส่งคําขอ
fetch
เพื่อรับส่วนเริ่มต้นของรูปภาพที่มีข้อมูลเมตา Exif - ระบบจะแปลงข้อมูลรูปภาพเป็น
ArrayBuffer
- ระบบใช้สคริปต์
exif-reader
เพื่อดึงข้อมูลเมตา Exif จากรูปภาพ - ระบบจะคัดลอกข้อมูลเมตาเพื่อสร้างสตริง HTML ซึ่งจะสร้างโปรแกรมดูข้อมูลเมตา
ตอนนี้แตกต่างจากการใช้ลักษณะการทำงานเดิม แต่เป็นการใช้ Web Worker
ลักษณะของเทรดหลักที่มี Web Worker
ตอนนี้คุณก็ได้เห็นลักษณะของการดึงข้อมูลข้อมูลเมตา Exif จากไฟล์ JPEG บนเทรดหลักแล้ว ลองดูว่าการทำงานบนเว็บมีลักษณะเป็นอย่างไร เช่น
- เปิดแท็บอื่นใน Chrome และเปิดเครื่องมือสำหรับนักพัฒนาเว็บ
- เปิดแผงประสิทธิภาพ
- ไปที่ https://exif-worker.glitch.me/with-worker.html
- ในแผงประสิทธิภาพ ให้คลิกปุ่มบันทึกที่มุมขวาบนของแผงเครื่องมือสำหรับนักพัฒนาเว็บ
- วาง ลิงก์รูปภาพนี้ ในช่อง และคลิกปุ่ม รับ JPEG!
- เมื่ออินเทอร์เฟซสร้างข้อมูลเมตา Exif แล้ว ให้คลิกปุ่มบันทึกอีกครั้งเพื่อหยุดการบันทึก
นี่คือพลังของ Web Worker แทนที่จะทำทุกอย่างในเทรดหลัก ทุกอย่างยกเว้นการใส่โปรแกรมดูข้อมูลเมตาด้วย HTML จะเสร็จสิ้นในเทรดแยกต่างหาก ซึ่งหมายความว่าเทรดหลักจะมีพื้นที่ว่างเพื่อทํางานอื่นๆ ได้
บางทีข้อได้เปรียบที่สำคัญที่สุดก็คือ สคริปต์ exif-reader
ไม่ได้โหลดบนเทรดหลัก แต่โหลดในเทรดของ Web Worker ต่างจากเวอร์ชันของแอปนี้ที่ไม่ได้ใช้โปรแกรมทำงานบนเว็บ ซึ่งหมายความว่าค่าใช้จ่ายในการดาวน์โหลด แยกวิเคราะห์ และคอมไพล์สคริปต์ exif-reader
จะเกิดขึ้นจากเทรดหลัก
มาเจาะลึกโค้ด Web Work ที่ทำให้ทั้งหมดนี้เกิดขึ้นได้กัน
ดูรหัส Web Worker
แค่ดูความแตกต่างที่ Web Worker สร้างก็ยังไม่เพียงพอ อย่างน้อยก็ต้องเข้าใจด้วยว่าโค้ดมีลักษณะอย่างไร อย่างน้อยในกรณีนี้ก็จะช่วยให้ทราบว่าโค้ดดังกล่าวมีอะไรบ้างที่เป็นไปได้ในขอบเขตของ Web Worker
เริ่มต้นด้วยรหัสเทรดหลักที่จำเป็นเพื่อให้ Web Worker เข้าสู่รูปภาพได้ ดังนี้
// scripts.js
// Register the Exif reader web worker:
const exifWorker = new Worker('/js/with-worker/exif-worker.js');
// We have to send image requests through this proxy due to CORS limitations:
const imageFetchPrefix = 'https://res.cloudinary.com/demo/image/fetch/';
// Necessary elements we need to select:
const imageFetchPanel = document.getElementById('image-fetch');
const imageExifDataPanel = document.getElementById('image-exif-data');
const exifDataPanel = document.getElementById('exif-data');
const imageInput = document.getElementById('image-url');
// What to do when the form is submitted.
document.getElementById('image-form').addEventListener('submit', event => {
// Don't let the form submit by default:
event.preventDefault();
// Send the image URL to the web worker on submit:
exifWorker.postMessage(`${imageFetchPrefix}${imageInput.value}`);
});
// This listens for the Exif metadata to come back from the web worker:
exifWorker.addEventListener('message', ({ data }) => {
// This populates the Exif metadata viewer:
exifDataPanel.innerHTML = data.message;
imageFetchPanel.style.display = 'none';
imageExifDataPanel.style.display = 'block';
});
โค้ดนี้จะทำงานบนเทรดหลัก และตั้งค่าแบบฟอร์มเพื่อส่ง URL ของรูปภาพไปยัง
Web Worker จากนั้น โค้ด Web Worker จะเริ่มด้วยคำสั่ง importScripts
ซึ่งโหลดสคริปต์ exif-reader
ภายนอก จากนั้นตั้งค่าไปป์ไลน์การรับส่งข้อความไปยังเทรดหลัก
// exif-worker.js
// Import the exif-reader script:
importScripts('/js/with-worker/exifreader.js');
// Set up a messaging pipeline to send the Exif data to the `window`:
self.addEventListener('message', ({ data }) => {
getExifDataFromImage(data).then(status => {
self.postMessage(status);
});
});
JavaScript ส่วนเล็กๆ นี้จะตั้งค่าไปป์ไลน์การรับส่งข้อความ เพื่อให้ผู้ใช้ส่งแบบฟอร์มที่มี URL ไปยังไฟล์ JPEG URL ดังกล่าวจะมาถึง Web Worker
จากนั้นโค้ดส่วนถัดไปนี้จะดึงข้อมูลเมตา Exif จากไฟล์ JPEG, สร้างสตริง HTML และส่ง HTML นั้นกลับไปที่ window
เพื่อแสดงต่อผู้ใช้ในท้ายที่สุด
// Takes a blob to transform the image data into an `ArrayBuffer`:
// NOTE: these promises are simplified for readability, and don't include
// rejections on failures. Check out the complete web worker code:
// https://glitch.com/edit/#!/exif-worker?path=js%2Fwith-worker%2Fexif-worker.js%3A10%3A5
const readBlobAsArrayBuffer = blob => new Promise(resolve => {
const reader = new FileReader();
reader.onload = () => {
resolve(reader.result);
};
reader.readAsArrayBuffer(blob);
});
// Takes the Exif metadata and converts it to a markup string to
// display in the Exif metadata viewer in the DOM:
const exifToMarkup = exif => Object.entries(exif).map(([exifNode, exifData]) => {
return `
<details>
<summary>
<h2>${exifNode}</h2>
</summary>
<p>${exifNode === 'base64' ? `<img src="data:image/jpeg;base64,${exifData}">` : typeof exifData.value === 'undefined' ? exifData : exifData.description || exifData.value}</p>
</details>
`;
}).join('');
// Fetches a partial image and gets its Exif data
const getExifDataFromImage = imageUrl => new Promise(resolve => {
fetch(imageUrl, {
headers: {
// Use a range request to only download the first 64 KiB of an image.
// This ensures bandwidth isn't wasted by downloading what may be a huge
// JPEG file when all that's needed is the metadata.
'Range': `bytes=0-${2 ** 10 * 64}`
}
}).then(response => {
if (response.ok) {
return response.clone().blob();
}
}).then(responseBlob => {
readBlobAsArrayBuffer(responseBlob).then(arrayBuffer => {
const tags = ExifReader.load(arrayBuffer, {
expanded: true
});
resolve({
status: true,
message: Object.values(tags).map(tag => exifToMarkup(tag)).join('')
});
});
});
});
ถึงจะอ่านยาก แต่ก็เป็นกรณีการใช้งานที่ค่อนข้างเกี่ยวข้องสำหรับผู้ปฏิบัติงานเกี่ยวกับเว็บเช่นกัน
อย่างไรก็ตาม ผลลัพธ์ที่ได้ก็คุ้มค่ากับการลงทุน ไม่ได้จำกัดเฉพาะกรณีการใช้งานนี้
คุณสามารถใช้ Web Worker กับสิ่งต่างๆ ได้มากมาย เช่น การแยกการเรียก fetch
และการประมวลผลคำตอบ การประมวลผลข้อมูลจำนวนมากโดยไม่บล็อกเทรดหลัก และนี่เป็นเพียงการเริ่มต้นเท่านั้น
เมื่อปรับปรุงประสิทธิภาพของเว็บแอปพลิเคชัน ให้เริ่มคิดถึงสิ่งที่สามารถทำได้อย่างสมเหตุสมผลในบริบทของ Web Worker สิ่งที่เป็นประโยชน์นี้อาจมีนัยสำคัญและสามารถช่วยให้ผู้ใช้ได้รับประสบการณ์โดยรวมที่ดีขึ้นสำหรับเว็บไซต์ของคุณได้