일.Web Workers 란 무엇인가
Web Workers 는 태스크를 백그라운드 스레드에서 실행하는 것을 지원하는 메커니즘입니다. 맞습니다, Web Worker 는동작이 제한된 멀티스레드를 제공합니다
브라우저 내 js 의 실행 환경은 여전히 싱글스레드이지만, 멀티스레드는 브라우저에는 예전부터 존재했습니다. 예를 들어 비동기 XHR 은 동작이 제한된 스레드이며, 메인 스레드에서 독립되어 있고, 내장된 메시지 메커니즘을 통해 통신하며, 일반적인 멀티스레드의 병행 문제는 존재하지 않습니다
Web Workers 는 메인 스레드에서 독립된 context 를 제공하며, 이 context 내에서는 제한된 API 를 사용할 수 있습니다 (DOM 조작은 금지, Cache 에 접근하지 못할 수 있음 등). 멀티스레드의 가장 큰 장점은 UI 를 블록하지 않는다는 것으로, 멀티스레드를 사용하여 시간이 많이 걸리는 태스크 (예: 오디오/비디오 디코딩, 및 이를 기반으로 한 데이터 처리) 를 완료할 수 있습니다. API 가 허용한다면, Web Workers 를 사용하여 XHR 을 직접 구현할 수도 있습니다
P.S.Web Worker 가 Cache 에 접근하는 것을 허용할かどうか는 현재 (2015/11/29) 아직 논쟁 중입니다. Chrome43 과 FF 는 지원하며, IE 와 Safari 의 지원 상황은 알 수 없습니다
약간의 잡담:Google 의 Gears 플러그인은 Worker Pool API 를 제안했습니다. 그것이 Web Workers 의 "원형"입니다. 처음에는 브라우저 기능을 강화하기를 희망했습니다. 예를 들어 오프라인 브라우징 지원 (오프라인에서 캐시 페이지에 접근하고, 재온라인 후 오프라인 작업을 제출) 등이지만, 현재 (2015/11/29) 는 이미 폐기되었습니다
Google Gears API
The Google Gears API is no longer available. Thank you for your interest.
이.Web Workers 는 무엇에 유용한가
백그라운드 스레드의 가장 큰 역할은 do stuff 입니다. 백그라운드 스레드를 지원하는 것은 브라우저가 더 많고 더 무거운 태스크를 감당할 수 있음을 의미합니다. 서버 측이 담당하던 일부 연산 (예: 정렬, 인코딩/디코딩, 템플릿 생성) 을 클라이언트 측으로 이관하여 서버 측의 압력을 경감할 수 있습니다. 사용자 경험에 영향을 주지 않으면서 (서버 측의 결과를 기다리는 것도, 로컬의 다른 스레드의 결과를 기다리는 것도 모두 대기이며, 후자가 더 빠를 수 있습니다)
필자는 Web Workers 에는 다음과 같은 적용 시나리오가 있다고 생각합니다:
- 오디오/비디오 디코딩
audioContext.decodeAudioData 등의 조작을 시도해 보면, "무거운 일"을 할 수 있는 백그라운드 스레드를 절실히 필요로 한다는 것을 알게 될 것입니다
- 이미지 전처리
예를 들어 아바타 업로드 전의 자르기, 심지어 워터마크 추가, 합성, 모자이크 추가 등. 클라이언트 측에서 완료할 수 있다면 대량의 임시 파일 전송을 피할 수 있습니다
- 정렬 등의 데이터 처리 알고리즘
서버 압력 경감
- 클라이언트 템플릿
예를 들어 markdown, 또는 서버 측이 JSON 을 반환하고, 클라이언트 측이 취득한 후 백그라운드 스레드에 넘겨 해석하고, 템플릿 HTML 을 적용하여 페이지를 생성. 이러한 조작을 모두 클라이언트 측에서 완료하면, 전송해야 할 것이 더 적어집니다
삼.Web Workers 사용 방법
말할 수 있는 샘플 코드는 다음과 같습니다:
//--- 主 페이지
if (window.Worker) {
var worker = new Worker('worker.js');
var data = {a: 1, b: [1, 2, 3], c: 'string'};
worker.postMessage(data);
worker.onmessage = function(e) {
console.log('main thread received data');
console.log(e.data);
// 接到消息立即停止 worker,onerror 将不会触发
// worker.terminate();
// terminate 之后收不到后续消息,但 post 不报错
// worker.postMessage(1);
}
worker.onerror = function(err) {
console.log('main thread received err');
console.log(err.message);
// 阻止报错
err.preventDefault();
}
}
//---end 主 페이지
//---worker.js
// 可以引入其它依赖
// importScripts('lib.js');
// importScripts('a.js', 'b.js');
onmessage = function(e) {console.log(self); // 看看 global 变量身上有些什么
var data = e.data;
console.log('worker received data');
console.log(data);
var res = data;
res.resolved = true;
postMessage(res);
setTimeout(function() {
throw new Error('error occurs');
// close,立即停止,相当于主线程中的 worker.terminate()
// close();
}, 100);
};
//---end worker.js
주의:
-
worker의 global context 는window가아니라,self입니다.self도 일련의 인터페이스를 제공하며,self.JSON,self.Math,self.console등을 포함합니다. 가장 직관적인 차이는document객체가 없어지지만,location,navigator는 남아 있습니다 -
Worker 의 원형은 DedicatedWorkerGlobalScope 로, SharedWGS 와는 다릅니다. Worker 는 전용이며, Worker 를 생성한 스크립트만이 자신이 생성한 worker 에 접근할 수 있습니다
-
worker내에서는 DOM 조작이 허용되지 않지만, WebSocket, IndexedDB, XHR 등을 지원합니다. 각 브라우저의 지원 상황에는 차이가 있습니다. 자세한 내용은 Functions and classes available to Web Workers - Web APIs | MDN 를 참조하십시오
주의:XHR 은 사용할 수 있지만, XHR 객체의 responseXML 와 channel 속성은 항상 null 을 반환합니다
-
메인 스레드와 worker 스레드는 메시지 송수신 방식이 일치합니다 (
postMessage로 전송,onmessage/onerror로 수신, 데이터는 MessageEvent 의data속성에서 취득). 스레드 간에 전달되는 것은 값의 copy 이지, 공유 참조가 아닙니다 -
IE10 과 FF 는
worker내에서의 Worker new 를 지원합니다. 이러한 worker 가 부모 페이지와 동원이어야 합니다 -
지원성 문제에 대해서는 기능 감지를行うことを 권장합니다
if (window.Worker) { // new Worker... } -
importScripts는 다른 js 파일을 도입할 수 있습니다. 외부 파일 내의 글로벌 변수는self에 붙여지며,worker내에서 직접 참조할 수 있습니다.importScripts는 동기적이며, 다운로드와 실행 완료 후 다음 행을 실행합니다
사.Shared Worker
위에서 주목한 Worker 는 dedicated worker(전용 worker) 에 속하며, worker 객체를 생성한 context 만이 worker 에 대한 접근권을 가집니다. Shared Worker 는 cross context 의 worker 공유를 지원합니다. 예를 들어 window 와 iframe, iframe 과 iframe
그것들은 공유 속성을 가지므로, 다른 윈도우 내의 애플리케이션의 같은 상태를 유지할 수 있으며, 다른 윈도우의 페이지는 동일한 공유 worker 스크립트를 통해 상태를 유지 및 보고합니다
localStorage 를 사용해도 상태 동기화를 실현할 수 있습니다. zxx 선배의 예: Page Visibility( 网页可见性) API 와 로그인 동기화 유도 페이지 实例 페이지. 흥미가 있으면 원문을 참조하십시오: Page Visibility( 페이지 가시성) API 소개, 미확장
필자가 생각할 수 있는 Shared Worker 의 유일한 적용 시나리오는 애플리케이션 상태 동기화 메커니즘의 구현일 것입니다. cookie, localStorage 도 상태를 저장할 수 있지만, Shared Worker 는 일련의 복잡한 상태 제어 메커니즘을 실현할 수 있습니다. 간단히 말해, cookie 와 localStorage 에는 데이터만 넣을 수 있지만, Shared Worker 에는 데이터를 넣을 수 있을 뿐만 아니라 코드도 실행할 수 있습니다
게다가, Shared Worker 는 별로 유용하지 않은 것 같습니다. 결국 new Worker 할 수 있는已经很不错了.锦上添花의 것의 역할은 사람을 놀라게 하지 않을 것입니다
샘플 코드는 다음과 같습니다:
//--- 主 페이지
if (window.SharedWorker) {
var sworker = new SharedWorker('sharedworker.js');
// 1.onmessage 隐式调用 start
// sworker.port.onmessage = function(e) {
// console.log('main thread received data:');
// console.log(e.data);
// }
// 2.或者 addEventListener 再显式调用 start
sworker.port.addEventListener('message', function(e) {
console.log('main thread received data:');
console.log(e.data);
});
sworker.port.start();
sworker.port.postMessage([1, 2, 3]);
}
//---end 主 페이지
//---sharedworker.js
var count = 0;
onconnect = function(e) {
// 记录连接数
count++;
var port = e.ports[0];
// 1.onmessage 隐式调用 start
port.onmessage = function(e) {
//!!! console.log 失效了
console.log('will not occur in console');
port.postMessage({receivedData: e.data, count: count});
//!!! 错误不会抛回给 sharedworker 创建者,静默失败
//!!! 如果 sharedworker 本身有语法错误,也会静默失败,而且在这之前的 postMessage 也将无效
// a*; // 制造一个语法错误
setTimeout(function() {
throw new Error('error occurs');
}, 100);
};
// 2.或者 addEventListener 再显式调用 start
// port.addEventListener('message', function(e) {
// //!!! console.log 失效了
// console.log('will not occur in console');
// port.postMessage('sharedworker received data: ' + e.data);
// });
// port.start();
};
//---end sharedworker.js
온라인 DEMO: testSharedWorker DEMO
테스트 방법:위의 링크를 열고, console 을見て count 가 1 인 것을 확인. 어떻게 리프레시해도 1 그대로. 다른 탭에서 해당 페이지를 열면, count 가 2 가 됨. 그 후 리프레시를 반복하면, count 가 5 가 됨. 이전의 탭으로 돌아가, 리프레시하면, count 가 6 이 됨...
오.스레드 안전 문제
스레드 안전의 면에서는, 병행에 의해 야기되는各种问题는존재하지 않습니다. Worker 스레드의 동작은 제한되어 있기 때문입니다 (worker 는 비스레드 안전한 컴포넌트와 DOM 에 접근할 수 없습니다)
육.기타 Worker
위에서 논의한 Web Workers 외에, 이러한 Worker 가 있습니다:
-
ServiceWorkers( 프록시 서버에 유사하며, 오프라인 서비스를 제공)
-
ChromeWorker( 브라우저 플러그인 개발에서 사용 가능한 Worker)
-
Audio Workers( 오디오 처리를 지원, 브라우저 지원 없음, 2015/11/29 현재)
참고 자료
-
Using Web Workers - Web APIs | MDN:不要 中文版을 보다, 번역 내용이 오래되었습니다
아직 댓글이 없습니다