내가 알 수있는 한 웹 작업자는 별도의 JavaScript 파일로 작성하고 다음과 같이 호출해야합니다.
new Worker('longrunning.js')
클로저 컴파일러를 사용하여 모든 JavaScript 소스 코드를 결합하고 최소화하고 있으며 배포를 위해 작업자를 별도의 파일로 만들 필요가 없습니다. 이것을 할 수있는 방법이 있습니까?
new Worker(function() {
//Long-running work here
});
일류 함수가 JavaScript에 매우 중요하기 때문에 백그라운드 작업을 수행하는 표준 방법이 웹 서버에서 다른 JavaScript 파일을 모두로드해야하는 이유는 무엇입니까?
답변
http://www.html5rocks.com/en/tutorials/workers/basics/#toc-inlineworkers
작업자 스크립트를 즉석에서 만들거나 별도의 작업자 파일을 만들지 않고 자체 포함 된 페이지를 만들려면 어떻게해야합니까? Blob ()을 사용하면 작업자 코드에 대한 URL 핸들을 문자열로 만들어 기본 논리와 동일한 HTML 파일에서 작업자를 “인라인”할 수 있습니다
BLOB 인라인 작업자의 전체 예 :
<!DOCTYPE html>
<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>
var blob = new Blob([
document.querySelector('#worker1').textContent
], { type: "text/javascript" })
// Note: window.webkitURL.createObjectURL() in Chrome 10+.
var worker = new Worker(window.URL.createObjectURL(blob));
worker.onmessage = function(e) {
console.log("Received: " + e.data);
}
worker.postMessage("hello"); // Start the worker.
</script>
답변
HTML에 웹 워커 코드를 포함시키는 html5rocks 솔루션은 상당히 끔찍합니다.
그리고 이스케이프 된 JavaScript-as-a-string 문자열은 작업 흐름을 복잡하게하기 때문에 더 나쁘지 않습니다 (클로저 컴파일러는 문자열에서 작동 할 수 없음).
개인적으로 나는 toString 메소드를 정말 좋아하지만 @ dan-man 정규식!
내가 선호하는 접근법 :
// Build a worker from an anonymous function body
var blobURL = URL.createObjectURL( new Blob([ '(',
function(){
//Long-running work here
}.toString(),
')()' ], { type: 'application/javascript' } ) ),
worker = new Worker( blobURL );
// Won't be needing this anymore
URL.revokeObjectURL( blobURL );
지원은이 세 테이블의 교차점입니다.
- http://caniuse.com/#feat=webworkers
- http://caniuse.com/#feat=blobbuilder
- http://caniuse.com/#feat=bloburls
그러나 선택적 ‘name’매개 변수가 일치하더라도 URL이 정확히 일치해야하므로 SharedWorker 에서는 작동하지 않습니다 . SharedWorker의 경우 별도의 JavaScript 파일이 필요합니다.
2015 년 업데이트-ServiceWorker 특이점 도착
이제이 문제를 해결하는 훨씬 더 강력한 방법이 있습니다. 다시 작업자 코드를 정적 문자열이 아닌 함수로 저장하고 .toString ()을 사용하여 변환 한 다음 선택한 정적 URL 아래의 CacheStorage에 코드를 삽입하십시오.
// Post code from window to ServiceWorker...
navigator.serviceWorker.controller.postMessage(
[ '/my_workers/worker1.js', '(' + workerFunction1.toString() + ')()' ]
);
// Insert via ServiceWorker.onmessage. Or directly once window.caches is exposed
caches.open( 'myCache' ).then( function( cache )
{
cache.put( '/my_workers/worker1.js',
new Response( workerScript, { headers: {'content-type':'application/javascript'}})
);
});
두 가지 가능한 대체가 있습니다. 위와 같이 또는 더 매끄럽게 ObjectURL은 /my_workers/worker1.js에 실제 JavaScript 파일을 넣습니다.
이 방법의 장점은 다음과 같습니다.
- SharedWorkers도 지원할 수 있습니다.
- 탭은 고정 주소에서 단일 캐시 사본을 공유 할 수 있습니다. Blob 접근 방식은 모든 탭에 대해 임의의 objectURL을 확산시킵니다.
답변
실행 컨텍스트를 인식하고 상위 스크립트와 작업자 역할을 모두 수행 할 수있는 단일 JavaScript 파일을 작성할 수 있습니다. 다음과 같은 파일의 기본 구조부터 시작하겠습니다.
(function(global) {
var is_worker = !this.document;
var script_path = is_worker ? null : (function() {
// append random number and time to ID
var id = (Math.random()+''+(+new Date)).substring(2);
document.write('<script id="wts' + id + '"></script>');
return document.getElementById('wts' + id).
previousSibling.src;
})();
function msg_parent(e) {
// event handler for parent -> worker messages
}
function msg_worker(e) {
// event handler for worker -> parent messages
}
function new_worker() {
var w = new Worker(script_path);
w.addEventListener('message', msg_worker, false);
return w;
}
if (is_worker)
global.addEventListener('message', msg_parent, false);
// put the rest of your library here
// to spawn a worker, use new_worker()
})(this);
보시다시피, 스크립트에는 부모와 작업자의 관점 모두에 대한 모든 코드가 포함되어 있으며, 개별 인스턴스가의 작업자인지 확인합니다 !document
. script_path
제공되는 경로 new Worker
가 스크립트가 아닌 상위 페이지를 기준으로하기 때문에 다소 다루기 어려운 계산이 상위 페이지를 기준으로 스크립트의 경로를 정확하게 계산하는 데 사용됩니다 .
답변
이 Blob
방법을 사용하면 작업자 팩토리의 경우는 어떻습니까?
var BuildWorker = function(foo){
var str = foo.toString()
.match(/^\s*function\s*\(\s*\)\s*\{(([\s\S](?!\}$))*[\s\S])/)[1];
return new Worker(window.URL.createObjectURL(
new Blob([str],{type:'text/javascript'})));
}
그래서 당신은 이것을 이렇게 사용할 수 있습니다 …
var myWorker = BuildWorker(function(){
//first line of worker
self.onmessage(){....};
//last line of worker
});
편집하다:
교차 스레드 통신을보다 쉽게 수행 할 수 있도록이 아이디어를 더 확장했습니다 : bridged-worker.js .
편집 2 :
위의 링크는 내가 만든 요점에 대한 것입니다. 다른 누군가가 나중에 그것을 실제 저장소 로 바 꾸었습니다 .
답변
웹 워커는 개별 프로그램과는 완전히 다른 맥락에서 작동합니다.
이는 코드가 다른 컨텍스트에 속하는 클로저를 통해 개체를 참조 할 수 있기 때문에 한 컨텍스트에서 다른 컨텍스트로 코드를 이동할 수 없음을 의미합니다.
이는 ECMAScript가 단일 스레드 언어로 설계 되었기 때문에 특히 중요하며 웹 작업자는 별도의 스레드로 작동하므로 스레드로부터 안전하지 않은 작업이 수행 될 위험이 있습니다.
이것은 다시 웹 워커가 소스 형식의 코드로 초기화되어야 함을 의미합니다.
WHATWG 의 사양에 따르면
결과 절대 URL의 원점이 입력 스크립트의 원점과 동일하지 않은 경우 SECURITY_ERR 예외를 발생시킵니다.
따라서 스크립트는 원본 페이지와 동일한 체계를 가진 외부 파일이어야합니다. 데이터 : URL 또는 javascript : URL에서 스크립트를로드 할 수 없으며 https : 페이지는 http : URL이있는 스크립트를 사용하여 작업자를 시작할 수 없습니다.
그러나 불행히도 소스 코드가있는 문자열을 생성자에 전달할 수 없었던 이유를 실제로 설명하지 못합니다.
답변
인라인 작업자를위한 더 나은 방법 읽기
var worker_fn = function(e)
{
self.postMessage('msg from worker');
};
var blob = new Blob(["onmessage ="+worker_fn.toString()], { type: "text/javascript" });
var worker = new Worker(window.URL.createObjectURL(blob));
worker.onmessage = function(e)
{
alert(e.data);
};
worker.postMessage("start");
답변
Adria의 응답을 취하여 현재 Chrome 및 FF에서는 작동하지만 IE10에서는 작동하지 않는 복사 가능한 복사 가능 기능에 넣습니다 (blob의 작업자는 보안 오류 발생 ).
var newWorker = function (funcObj) {
// Build a worker from an anonymous function body
var blobURL = URL.createObjectURL(new Blob(
['(', funcObj.toString(), ')()'],
{type: 'application/javascript'}
));
var worker = new Worker(blobURL);
// Won't be needing this anymore
URL.revokeObjectURL(blobURL);
return worker;
}
다음은 실제 예입니다. http://jsfiddle.net/ubershmekel/YYzvr/