[javascript] 별도의 자바 스크립트 파일이없는 웹 워커?

내가 알 수있는 한 웹 작업자는 별도의 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 );

지원은이 세 테이블의 교차점입니다.

그러나 선택적 ‘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 파일을 넣습니다.

이 방법의 장점은 다음과 같습니다.

  1. SharedWorkers도 지원할 수 있습니다.
  2. 탭은 고정 주소에서 단일 캐시 사본을 공유 할 수 있습니다. 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/