"MV3 service worker 는 user 관점에서 두 상태밖에 없어: '지금 뭔가 하는 중' 과 'idle, evict 됐을 수도'. 그 on/off 형태 위에 설계하는 게 Track 2 의 전체 mental model."
Idle clock 은 즉시 시작
Worker 의 마지막 in-flight event 가 완료되는 순간, Chrome 이 clock 을 시작. 약 30 초 무활동 — event fire 없음, async 작업 pending 없음, in-flight Promise 없음 — 후 worker evict. 메모리 해제. Global 사라짐. Module-level Map 과 Set 증발.
Clock 은 memory pressure 또는 Chrome 내부 휴리스틱이 worker 가 안 쓸모 있다고 판단하면 더 빨리 만료. 30 초는 soft maximum 으로 다뤄, 보장 아냐.
Worker 를 깨우는 것
Worker 가 listener 등록한 어떤 event 든. 큰 것들:
chrome.runtime.onMessage— popup, content script, 또는 다른 extension 이 message 보냄chrome.alarms.onAlarm— 예약된 alarm fire (setTimeout/setInterval의 MV3 대체)chrome.tabs.*event — tab created / updated / removed / activated / replacedchrome.runtime.onInstalled/onStartup— extension install 또는 Chrome launchchrome.runtime.onConnect— popup 또는 content script 에서 long-lived port 열림chrome.webNavigation.*— page navigation event (webNavigation permission 필요)chrome.contextMenus.onClicked— user 가 등록된 context menu entry 활성화chrome.action.onClicked—default_popup없는 상태에서 toolbar icon 클릭
이 중 어느 게 fire 하면 Chrome 이 worker 를 cold 로 깨워: background.js 위 부분 다시 실행, listener 재등록 (이게 중요 — 등록이 Chrome 한테 dispatch 하라는 신호), 그 다음 Chrome 이 event 전달.
Eviction 때 죽는 것
Worker evict 때 잃는 거:
- Module-level 변수 (
let counter = 0,const cache = new Map()등) - In-flight Promise (cancel 됨;
.thenchain 절대 fire 안 함) - WebSocket 연결, EventSource 연결, MediaStream handle, BroadcastChannel port
- Listener 안에서 이전 wake 에 set 된 closure-captured state
살아남는 거:
chrome.storage.local— eviction 전에 write 됐으면 다음 wake 에 read 가능chrome.storage.session— 2023 추가; worker eviction 견디지만 browser session 끝나면 죽음chrome.alarms— 등록된 alarm 은 worker 재시작 너머로 영속- 등록된 listener 자체 (Chrome 이 기억;
background.js위 부분 재실행이 재attach 메커니즘)
Cold-wake 패턴
Cold wake = worker 가 매번 1 행에서부터 실행. background.js 를 매 event 마다 도는 main() 함수처럼 다뤄:
- 해당 handler 위에서 필요한 state 를
chrome.storage에서 read. - 일 하기.
- 새 state 를
chrome.storage로 write back. - Handler return (또는 Promise resolve).
- Worker idle 됨. 결국 evict. 다음 event 대기.
가장 깔끔한 mental model: 모든 event handler 가 전체 프로그램. Read / work / write / return.
피할 anti-pattern
MV2 에선 멀쩡해 보이지만 MV3 에선 능동적으로 깨지는 패턴:
- 주기적 작업에
setInterval(fn, 60000)— timer 가 fire 하기 전에 worker evict 가능.chrome.alarms.create({periodInMinutes: 1})사용; alarm 은 eviction 너머로 영속하고 worker 다시 깨움. - Module-level cache (
const userCache = new Map()). 매 wake 마다 reset. Value 에 명시적 expiry timestamp 박아서chrome.storage.local사용. - Long-lived WebSocket / EventSource hold. Worker eviction 이 죽임. 진짜 필요하면 event 마다 재수립; 또는 user 가 계속 여는 tab 의 content script 에 연결 옮김.
- Event 사이 "session state" 로 global 쓰기. Module-level 변수는 항상 ephemeral 로 다뤄. 잠깐 살아남는 것처럼 보여도 의존하지 마.
chrome.storage 언급 없는 옛 답변은 의심해.