Web Workers API, OffscreenCanvas 학습노트
- Nest
- Development
- Category
- Javascript
- Hit
- 124
- Star
- 0
동작 공간을 분리시켜 부하를 줄이는 역할을 할 수 있나보다.
활용할 수 있는 분야가 많아서 학습이 필요하여 노트를 작성하면서 연구를 시작한다.
참고링크
- docs: mdn web docs
- youtube video: https://www.youtube.com/watch?v=6stSvXYwnjU
- Web Worker 간단 정리하기
vite에서 worker.js 파일 사용하기
일반적인 파일을 불러오는거랑 같아서 vite같은 트랜스파일링을 사용하는 환경에서 불러오면 public
디렉토리에다 worker.js 파일을 넣고 사용해야한다.
하지만 관리상 좋은 모습은 아니라서 src 경로에다 넣고 사용하는 방법은 다음과 같이 불러올 수 있다.
const worker = new Worker(new URL('./worker.js', import.meta.url), { type: 'module' })
기본적으로 사용해보기
기초적으로 메시지를 주고받는 모습은 다음과 같다.worker.js
파일에서 열심히 처리하고 결과를 메시지를 넘겨주면 될듯하다.
// main.js
const worker = new Worker(new URL('./worker.js', import.meta.url), { type: 'module' })
console.group('main.js')
console.log('시작')
console.groupEnd()
worker.postMessage([ 1, 2 ])
worker.onmessage = function(e)
{
console.group('main.js')
console.log('메인파일에서 메시지를 받는다.')
console.log('data:', e.data)
console.groupEnd()
}
// worker.js
self.onmessage = function(e)
{
console.group('worker.js')
console.log('메인에서 메시지를 받았다.')
postMessage({
message: '메인으로 메시지를 보냅니다.',
data: e.data[0] * e.data[1],
})
console.log('222')
console.groupEnd()
}
worker.js
영역에서 처리를 하고 결과물을 postMessage
메서드로 보내주기만 하면 된다.worker.js
내부 메서드에서 self
값으로 WorkerGlobalScope
에 접근할 수 있다.
메지시를 전달하여 메인과 워커 쓰레드 영역에 값을 전달할 수 있고, 함수를 전달하려하면 오류가 발생된다.
활용처
메인 쓰레드에 영향을 주지않는데 사용되는쪽으로 생각하면 될거같은데.. 활용에 대하여 좀 생각해볼 필요가 있다.
- 네트워크 통신
- 로컬 스토리지, 인덱스db 처리
- 파일 시스템 입출력
- 백그라운드에서 오랫동안 작업해야하는 경우
- UI 작동에 방해없이 작업을 해야할때
- 웹소켓 처리
- 이미지 로딩 (Image 객체를 생성하지 않고도 이미지 로딩 상태, 성공, 실패 여부를 UI에 동적으로 업데이트할 수 있다.)
제약
worker.js
영역은 만능이 아니고 제약이 어느정도인지 알고있는것이 좋은거같다.
- dom 컨트롤 관련된쪽은 사용할 수 없다. (
new Image
같은걸 사용할 수 없다는 것이다.) - 메모리 공유하지 않는다. (다른 방법으로 공유 가능하지만 추천은 안한다고..)
마치 node.js 영역같은 인상이다.
structuredClone()
침고링크
데이터 전달을 위하여 깊은복사 함수인데 JSON.stringfy() 로 삽질을 안해도 되는 함수다.
OffscreenCanvas
다른 쓰레드에서 canvas 처리를 해주는듯한데.. 이미지 리사이즈 기능을 사용할때 사용할 수 있을거 같다.
잠깐 데모를 작성해보니 메인에서 워커로 캔버스 객체를 넘겨주고 웹 워커 내부에서 캔버스 객체 직접 컨트롤할 수 있었다. 이정도만 해도 정말로 감사한 일인듯하다. ㅎㄷ~
다음은 확인을 위한 데모코드다.
// main.js
const worker = new Worker(new URL('./worker.js', import.meta.url), { type: 'module' })
const canvas = document.createElement('canvas')
const offScreenCanvas = canvas.transferControlToOffscreen()
worker.postMessage({
canvas: offScreenCanvas,
src: 'image.jpg',
}, [ offScreenCanvas ])
document.body.appendChild(canvas)
// worker.js
addEventListener('message', async function(e) {
const { canvas, src } = e.data
const context = canvas.getContext('2d')
let image = await fetch(src)
image = await image.blob()
const bitmap = await createImageBitmap(image)
canvas.width = bitmap.width
canvas.height = bitmap.height
context.drawImage(bitmap, 0, 0)
})
참고링크
vite에서 빌드할때 inline으로 메인 스크립트 코드에 포함시키기
기본적으로 웹 워커의 파일은 별도로 불러와서 사용한다. 하지만 라이브러리 형태로 배포할때 왠만하면 하나의 파일로 합쳐서 배포하는것이 좋은점이 많다.
라이브러리를 웹 워커용으로 수정하고 빌드해보니 worker 파일이 따로 만들어졌다.
그래서 좀 찾아보니 다음과 같은 방법으로 워커를 불러오니 워커 코드가 uri 인코딩을 하여 문자로 바꿔버렸다.
import MyWorker from './worker.js?worker&inline'
const worker = new ImageResizeWorker()
정상적인 방법이 아닌거 같지만 잘 작동한다.;;
참고: https://vitejs.dev/guide/assets#importing-script-as-a-worker