마지막 모듈에서는 웹 작업자에 관한 개요가 제공되었습니다. 웹 작업자는 JavaScript를 기본 스레드에서 다른 곳으로 이동하여 입력 응답성을 개선 웹 작업자 스레드를 분리하여 웹사이트 상호작용 INP (다음 페인트)에 추가할 수 있습니다. 기본 스레드로 이동합니다. 개요만으로는 충분하지 않습니다. 이 모듈에서는 구체적인 사용 사례가 제공됩니다.
이러한 사용 사례로는 웹사이트에서 Exif 메타데이터를 이는 당연한 개념이 아닙니다. 실제로 Flickr 같은 웹사이트는 Exif 메타데이터로 볼 수 있어 API에 대한 기술적 세부 정보를 알 수 이미지(예: 색심도, 카메라 제조업체 및 모델) 데이터를 수집하는 데 사용됩니다
그러나 이미지를 가져와 ArrayBuffer
로 변환하는 로직은
Exif 메타데이터를 추출하는 작업은
확인할 수 있습니다. 다행히 웹 작업자 범위를 사용하면
기본 스레드를 벗어납니다. 그런 다음 웹 작업자의 메시징 파이프라인을 사용하여
Exif 메타데이터가 HTML 문자열로 기본 스레드에 다시 전송됩니다.
사용자에게 표시됩니다.
웹 작업자가 없는 기본 스레드의 모습
먼저 있습니다 이렇게 하려면 다음 단계를 따르세요.
- Chrome에서 새 탭을 열고 DevTools를 엽니다.
- 성능 패널을 엽니다.
- https://exif-worker.glitch.me/without-worker.html로 이동합니다.
- 성능 패널에서 오른쪽 상단에 있는 Record를 클릭합니다. 나타납니다.
- 이 이미지 링크 또는 Exif가 포함된 다른 링크를 붙여넣습니다. 메타데이터 파일을 선택하고 Get that JPEG! 버튼을 클릭합니다.
- 인터페이스가 Exif 메타데이터로 채워지면 Record를 다시 클릭하여 녹음을 중지합니다.
있을 수 있는 다른 스레드(예: 래스터라이저)는 제외하고 등의 작업을 수행합니다. 앱의 모든 작업은 기본 스레드에서 발생합니다. 기본 스레드가 발생하면 다음과 같은 상황이 발생합니다.
- 양식은 입력을 받고
fetch
요청을 전달하여 초기 URL을 가져옵니다. 부분(예: EXIF 메타데이터가 포함된 이미지의 일부)을 캡처합니다. - 이미지 데이터는
ArrayBuffer
로 변환됩니다. exif-reader
스크립트는 이미지- 메타데이터를 스크랩하여 HTML 문자열을 구성한 다음 메타데이터 뷰어입니다.
이제 동일한 동작을 구현하지만 근로자!
웹 작업자가 있는 기본 스레드의 모습
지금까지 이미지에서 Exif 메타데이터를 추출하는 과정을 살펴보았습니다. JPEG 파일이 있다면 웹에서 다음과 같은 경우
- Chrome에서 다른 탭을 열고 DevTools를 엽니다.
- 성능 패널을 엽니다.
- https://exif-worker.glitch.me/with-worker.html로 이동합니다.
- 공연 패널에서 오른쪽 상단에 있는 녹화 버튼을 클릭합니다. 나타납니다.
- 입력란에 This image link를 붙여넣고 Get that JPEG! 버튼을 클릭합니다.
- 인터페이스가 Exif 메타데이터로 채워지면 기록 버튼을 클릭합니다. 을 눌러 녹화를 중지합니다.
이는 웹 작업자의 힘입니다. 기본 설정에서 모든 작업을 HTML로 메타데이터 뷰어 채우기를 제외한 모든 작업은 별도의 스레드가 필요합니다. 즉, 기본 스레드가 해제되어 다른 작업을 할 수 있습니다.
아마도 가장 큰 장점은 앞서 얘기한 이 앱의 버전과는 달리
웹 워커를 사용하지 않으면 exif-reader
스크립트가 기본
스레드가 아니고 웹 작업자 스레드에 있습니다. 다시 말해
exif-reader
스크립트 다운로드, 파싱, 컴파일은
기본 스레드로 이동합니다.
이제 이 모든 작업을 가능하게 하는 웹 작업자 코드를 살펴보겠습니다.
웹 작업자 코드 살펴보기
웹 작업자가 만들어내는 차이를 보는 것만으로는 충분하지 않지만 이 경우에는 코드가 어떤 모양인지를 이해할 수 있기 때문에 가능한 한 많이 있습니다
<ph type="x-smartling-placeholder">웹 작업자가 작업을 수행하기 전에 발생해야 하는 기본 스레드 코드로 시작합니다. 사진 입력:
// 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을 전송할 양식을 설정합니다.
웹 작업자의 몫입니다 여기에서 웹 작업자 코드는 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이 웹 워커에 도착합니다.
거기에서 다음 비트 코드는 JPEG 파일에서 Exif 메타데이터를 추출합니다.
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('')
});
});
});
});
다소 읽기는 어렵지만 웹 작업자의 경우 상당히 관련 있는 사용 사례이기도 합니다.
그러나 결과는 이 사용 사례에만 국한되지 않고 노력할 가치가 있습니다.
fetch
호출 격리와 같은 모든 종류의 작업에 웹 작업자를 사용할 수 있습니다.
대량의 데이터를 처리하고
이는 시작에 불과합니다.
웹 애플리케이션의 성능을 개선할 때는 웹 작업자 컨텍스트에서 합리적으로 수행할 수 있는 모든 것입니다. 이점은 웹사이트의 사용자 환경을 전반적으로 개선할 수 있습니다.