ref. 1> The Worker Environment > Subworkers
각 worker 에 대해서 대부분의 browser 는 seperate process 를 만든다(spawn) 고 한다. 그리고 공유되는 data 는 전부 copy 로 이뤄진다고 한다.
Web worker 사용
- new Worker() : new Worker(URL) 을 통해 Worker 를 생성하고,
- worker.onmessage : worker 에서 넘어오는 message 를 처리할 worker.onmessage 를 정의해준다.
- worker.onerror : worker 에서 발생하는 error 를 처리할 함수를 정의해 준다.
- self.onmessage : .js 등 Worker 의 source code 에서는 postMessage 로 넘어오는 data 를 처리할 self.onmessage 를 정의한다.
- self.postMessage : 그리고 결과값등 main page 로 전달할 사항은 self.postMessage 로 넘겨준다.
- worker.postMessage() : worker 의 postMessage 를 호출하므로써 worker 의 동작을 시작할 수 있다.
위에서 정의하는 on* 함수는
- worker.addEventListener('message', func_name, false);
등의 방법으로도 정의할 수도 있다.
ref.2 에 있는 그림을 보면, 아래처럼 동작하는 것을 알 수 있다.
HTML, Worker.postMessage ----> Worker, self.onmessage Worker, self.postMessage ----> HTML, Worker.onmessage
ref. 1 > Full example 에 있는 code 를 분석해 보면, 아래와 같은 흐름을 보인다. worker.postMessage(); -> self.onmessage -> self.postMessage -> worker.onmessage
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
</head>
<body>
<div id="log"></div>
<script id="worker1" type="javascript/worker">
// This script won't be parsed by JS engines
// because its type is javascript/worker.
self.onmessage = function(e) {
self.postMessage('msg from worker');
};
// Rest of your worker code goes here.
</script>
<script>
function log(msg) {
// Use a fragment: browser will only render/reflow once.
var fragment = document.createDocumentFragment();
fragment.appendChild(document.createTextNode(msg));
fragment.appendChild(document.createElement('br'));
document.querySelector("#log").appendChild(fragment);
}
var blob = new Blob([document.querySelector('#worker1').textContent]);
var worker = new Worker(window.URL.createObjectURL(blob));
worker.onmessage = function(e) {
log("Received: " + e.data);
}
worker.postMessage(); // Start the worker.
</script>
</body>
</html>
Web Worker 개수
ref.3 의 개인적인 test 에 따르면 100개 이상에서 performance 가 느려졌다고 한다. 이 Tester 의 말로는 자신의 computer 에서는 8개가 가장 좋다고 했다.
Examples
Web Worker downloader
Web Worker 를 이용해서 XMLHttpRequest 로 download 를 하고 이것을 blob 으로 저장한 후 download 하는 예제이다.
http://localhost:8080/resources/download_test.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
</head>
<body>
<div id="log"></div>
<script id="worker1" type="javascript/worker">
// This script won't be parsed by JS engines
// because its type is javascript/worker.
self.onmessage = function(e) {
self.postMessage('msg from worker');
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://localhost:8080/resources/testflower.jpg', true);
xhr.responseType = 'blob';
xhr.onload = function(e) {
if (this.status == 200) {
// Note: .response instead of .responseText
var blob = new Blob([this.response], {type: 'image/png'});
self.postMessage(blob);
}
};
xhr.send();
self.postMessage('msg from worker2');
};
// Rest of your worker code goes here.
</script>
<script>
function log(msg) {
// Use a fragment: browser will only render/reflow once.
var fragment = document.createDocumentFragment();
fragment.appendChild(document.createTextNode(msg));
fragment.appendChild(document.createElement('br'));
document.querySelector("#log").appendChild(fragment);
}
var blob = new Blob([document.querySelector('#worker1').textContent]);
var worker = new Worker(window.URL.createObjectURL(blob));
worker.onmessage = function(e) {
log("Received: " + e.data);
console.log(e.data)
if(typeof e.data == "object"){
var a = document.getElementById('savelink');
a.href = window.URL.createObjectURL(e.data);
a.click();
}
}
worker.postMessage(""); // Start the worker.
</script>
<a id="savelink" download="hello.png" href="data:text/plain,Hello%20world!"></a>
</body>
</html>
Multiple Web Worker
아래 예제는 여러개의 Web Worker 를 이용해서 동시에 download 를 하는 예제이다.
http://localhost:8080/resources/download_test_2.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
</head>
<body>
<div id="log"></div>
<script id="worker1" type="javascript/worker">
// This script won't be parsed by JS engines
// because its type is javascript/worker.
self.onmessage = function(e) {
self.postMessage('msg from worker');
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://localhost:8080/resources/testflower.jpg', true);
xhr.responseType = 'blob';
xhr.onload = function(e) {
if (this.status == 200) {
// Note: .response instead of .responseText
var blob = new Blob([this.response], {type: 'image/png'});
self.postMessage(blob);
}
};
xhr.send();
self.postMessage('msg from worker2');
};
// Rest of your worker code goes here.
</script>
<script>
function log(msg) {
// Use a fragment: browser will only render/reflow once.
var fragment = document.createDocumentFragment();
fragment.appendChild(document.createTextNode(msg));
fragment.appendChild(document.createElement('br'));
document.querySelector("#log").appendChild(fragment);
}
function workerOnMessage(e) {
log("Received: " + e.data);
console.log(e.data)
if(typeof e.data == "object"){
var a = document.getElementById('savelink');
a.href = window.URL.createObjectURL(e.data);
a.click();
}
}
var blob = new Blob([document.querySelector('#worker1').textContent]);
var worker1 = new Worker(window.URL.createObjectURL(blob));
var worker2 = new Worker(window.URL.createObjectURL(blob));
var worker3 = new Worker(window.URL.createObjectURL(blob));
worker1.onmessage = workerOnMessage;
worker2.onmessage = workerOnMessage;
worker3.onmessage = workerOnMessage;
worker1.postMessage(""); // Start the worker.
worker2.postMessage(""); // Start the worker.
worker3.postMessage(""); // Start the worker.
</script>
<a id="savelink" download="hello.png" href="data:text/plain,Hello%20world!"></a>
</body>
</html>
참고로, Using web workers - Web developer guide | MDN 에 따르면 IE 10 은 Blob URIs 를 인자로 사용해서 Worker 를 생성할 수 없다. SecurityError 가 발생한다. 그래서 IE 에서 테스트를 하려면 worker 에 해당하는 script 를 따로 .js 로 만들어서 new Worker() 를 하자.
Web Worker uploader
inline 으로 worker 생성
from ref. 6
function createInlineWorker(fn) {
let blob = new Blob(['self.onmessage = ', fn.toString()], { type: 'text/javascript' });
let url = URL.createObjectURL(blob);
return new Worker(url);
}
let myWorker = createInlineWorker(function (e) {
self.postMessage(e.data.toUpperCase());
});
myWorker.onmessage = function (e) {
console.log(e.data); // HELLO FROM AN INLINE WORKER!
};
myWorker.postMessage('hello from an inline worker!')
References
- The Basics of Web Workers - HTML5 Rocks
- 박종명의 아름다운 개발 since 2010.06
- javascript - Number of Web Workers Limit - Stack Overflow
- Pro HTML5 Programming: Chapter 10 | Using the Web Workers API
- Blobs | O’Reilly | Javascript: The Definitive Guide | HTML5 APIs
- How to use Web Workers in Vue.js | Our Code World
댓글 없음:
댓글 쓰기