문자열에서 웹 작업자를 만드는 방법
POST 요청을 통해 제공되는 문자열에서 웹 워커 생성을 어떻게 사용할 수 있습니까?
제가 생각할 수있는 한 가지 방법은 구현 방법을 잘 모르겠습니다. 서버 응답에서 데이터 URI를 생성하고이를 Worker 생성자에 전달하는 것입니다.하지만 일부 브라우저에서는이를 허용하지 않는다고 들었습니다. 이것은 동일한 출처 정책 때문입니다.
MDN은 데이터 URI에 대한 출처 정책에 대한 불확실성을 명시합니다 .
참고 : 작업자 생성자의 매개 변수로 전달 된 URI는 동일 출처 정책을 따라야합니다. 현재 데이터 URI가 동일한 출처인지 여부에 대해 브라우저 공급 업체간에 의견이 일치하지 않습니다. Gecko 10.0 (Firefox 10.0 / Thunderbird 10.0) 이상에서는 작업자를위한 유효한 스크립트로 데이터 URI를 허용합니다. 다른 브라우저는 동의하지 않을 수 있습니다.
whatwg에 대해 논의 하는 게시물도 있습니다 .
요약
blob:
Chrome 8 이상, Firefox 6 이상, Safari 6.0 이상, Opera 15 이상data:application/javascript
Opera 10.60-12 용eval
그렇지 않으면 (IE 10+)
URL.createObjectURL(<Blob blob>)
문자열에서 웹 작업자를 만드는 데 사용할 수 있습니다. 더 이상 사용되지 않는BlobBuilder
API 또는 생성자를 사용하여 blob을 만들 수 있습니다 .Blob
데모 : http://jsfiddle.net/uqcFM/49/
// URL.createObjectURL
window.URL = window.URL || window.webkitURL;
// "Server response", used in all examples
var response = "self.onmessage=function(e){postMessage('Worker: '+e.data);}";
var blob;
try {
blob = new Blob([response], {type: 'application/javascript'});
} catch (e) { // Backwards-compatibility
window.BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder;
blob = new BlobBuilder();
blob.append(response);
blob = blob.getBlob();
}
var worker = new Worker(URL.createObjectURL(blob));
// Test, used in all examples:
worker.onmessage = function(e) {
alert('Response: ' + e.data);
};
worker.postMessage('Test');
적합성
웹 작업자는 다음 브라우저 소스 에서 지원됩니다 .
- 크롬 3
- Firefox 3.5
- IE 10
- 오페라 10.60
- Safari 4
이 메서드의 지원은 Blob
API 및 메서드의 지원을 기반으로합니다 URL.createObjectUrl
. Blob
호환성 :
- Chrome 8 이상 (
WebKitBlobBuilder
), 20 이상 (Blob
생성자) - Firefox 6 이상 (
MozBlobBuilder
), 13 이상 (Blob
생성자) - Safari 6+ (
Blob
생성자)
IE10은 MSBlobBuilder
및 URL.createObjectURL
. 그러나 blob:
-URL 에서 Web Worker를 만들려고 하면 SecurityError가 발생합니다.
Opera 12는 URL
API를 지원하지 않습니다 . 이 해킹URL
덕분에 일부 사용자는 개체 의 가짜 버전을 가질 수 있습니다 .browser.js
폴백 1 : 데이터 URI
Opera는 Worker
생성자에 대한 인수로 데이터 URI를 지원합니다 . 참고 : 특수 문자 (예 : #
및 %
) 를 이스케이프하는 것을 잊지 마십시오 .
// response as defined in the first example
var worker = new Worker('data:application/javascript,' +
encodeURIComponent(response) );
// ... Test as defined in the first example
데모 : http://jsfiddle.net/uqcFM/37/
폴백 2 : 평가
eval
Safari (<6) 및 IE 10의 대체 수단으로 사용할 수 있습니다.
// Worker-helper.js
self.onmessage = function(e) {
self.onmessage = null; // Clean-up
eval(e.data);
};
// Usage:
var worker = new Worker('Worker-helper.js');
// `response` as defined in the first example
worker.postMessage(response);
// .. Test as defined in the first example
현재 허용되는 답변에 동의하지만 작업자 코드를 문자열 형식으로 편집하고 관리하는 것이 종종 바쁠 것입니다.
따라서 선택적으로 작업자를 함수로 유지 한 다음 string-> blob으로 숨길 수있는 아래 접근 방식을 사용할 수 있습니다.
// function to be your worker
function workerFunction() {
var self = this;
self.onmessage = function(e) {
console.log('Received input: ', e.data); // message received from main thread
self.postMessage("Response back to main thread");
}
}
///////////////////////////////
var dataObj = '(' + workerFunction + ')();'; // here is the trick to convert the above fucntion to string
var blob = new Blob([dataObj.replace('"use strict";', '')]); // firefox adds "use strict"; to any function which might block worker execution so knock it off
var blobURL = (window.URL ? URL : webkitURL).createObjectURL(blob, {
type: 'application/javascript; charset=utf-8'
});
var worker = new Worker(blobURL); // spawn new worker
worker.onmessage = function(e) {
console.log('Worker said: ', e.data); // message received from worker
};
worker.postMessage("some input to worker"); // Send data to our worker.
이것은 IE11 + 및 FF 및 Chrome에서 테스트되었습니다.
대부분의 아이디어로 접근하고 내 아이디어를 추가했습니다. 내 코드가 작업자에게 필요한 유일한 것은 'self'범위를 참조하기 위해 'this'를 사용하는 것입니다. 나는 이것이 매우 즉흥적이라고 확신합니다.
// Sample code
var code = function() {
this.onmessage = function(e) {
this.postMessage('Worker: '+e.data);
this.postMessage('Worker2: '+e.data);
};
};
// New thread worker code
FakeWorkerCode = function(code, worker) {
code.call(this);
this.worker = worker;
}
FakeWorkerCode.prototype.postMessage = function(e) {
this.worker.onmessage({data: e});
}
// Main thread worker side
FakeWorker = function(code) {
this.code = new FakeWorkerCode(code, this);
}
FakeWorker.prototype.postMessage = function(e) {
this.code.onmessage({data: e});
}
// Utilities for generating workers
Utils = {
stringifyFunction: function(func) {
// Stringify the code
return '(' + func + ').call(self);';
},
generateWorker: function(code) {
// URL.createObjectURL
windowURL = window.URL || window.webkitURL;
var blob, worker;
var stringified = Utils.stringifyFunction(code);
try {
blob = new Blob([stringified], {type: 'application/javascript'});
} catch (e) { // Backwards-compatibility
window.BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder;
blob = new BlobBuilder();
blob.append(stringified);
blob = blob.getBlob();
}
if ("Worker" in window) {
worker = new Worker(windowURL.createObjectURL(blob));
} else {
worker = new FakeWorker(code);
}
return worker;
}
};
// Generate worker
var worker = Utils.generateWorker(code);
// Test, used in all examples:
worker.onmessage = function(e) {
alert('Response: ' + e.data);
};
function runWorker() {
worker.postMessage('working fine');
}
데모 : http://jsfiddle.net/8N6aR/
좋은 대답-저는 오늘 폴백 기능이있는 웹 작업자를 사용할 수 없을 때 (예 : 작업자 스크립트를 주 스레드에서 실행) 만들려고 할 때 비슷한 문제를 해결했습니다. 이 스레드는 주제와 관련이 있으므로 여기에 솔루션을 제공 할 것이라고 생각했습니다.
<script type="javascript/worker">
//WORKER FUNCTIONS
self.onmessage = function(event) {
postMessage('Hello, ' + event.data.name + '!');
}
</script>
<script type="text/javascript">
function inlineWorker(parts, params, callback) {
var URL = (window.URL || window.webkitURL);
if (!URL && window.Worker) {
var worker = new window.Worker(URL.createObjectURL(new Blob([parts], { "type" : "text/javascript" })));
worker.onmessage = function(event) {
callback(event.data);
};
worker.postMessage(params);
} else {
var postMessage = function(result) {
callback(result);
};
var self = {}; //'self' in scope of inlineWorker.
eval(parts); //Converts self.onmessage function string to function on self via nearest scope (previous line) - please email chrisgwgreen.site@gmail.com if this could be tidier.
self.onmessage({
data: params
});
}
}
inlineWorker(
document.querySelector('[type="javascript/worker"]').textContent,
{
name: 'Chaps!!'
},
function(result) {
document.body.innerHTML = result;
}
);
</script>
</body>
사용 사례에 따라 다음과 같은 것을 사용할 수 있습니다.
task.js Simplified interface for getting CPU intensive code to run on all cores (node.js, and web)
A example would be
// turn blocking pure function into a worker task
const functionFromPostRequest = task.wrap('function (exampleArgument) {}');
// run task on a autoscaling worker pool
functionFromPostRequest('exampleArgumentValue').then(result => {
// do something with result
});
Expanding on @Chanu_Sukarno's code, you can simply pass in a worker function (or string) to this function and it will execute it inside a web worker:
async function doWorkerTask(workerFunction, input, buffers) {
// Create worker
let fnString = '(' + workerFunction.toString().replace('"use strict";', '') + ')();';
let workerBlob = new Blob([fnString]);
let workerBlobURL = window.URL.createObjectURL(workerBlob, { type: 'application/javascript; charset=utf-8' });
let worker = new Worker(workerBlobURL);
// Run worker
return await new Promise(function(resolve, reject) {
worker.onmessage = function(e) { resolve(e.data); };
worker.postMessage(input, buffers);
});
}
Here's an example of how to use it:
function myTask() {
self.onmessage = function(e) {
// do stuff with `e.data`, then:
self.postMessage("my response");
self.close();
}
}
let output = await doWorkerTask(myTask, input, inputBuffers);
// now you can do something with `output` (which will be equal to "my response")
In nodejs, doWorkerTask
looks like this:
async function doWorkerTask(workerFunction, input, buffers) {
let Worker = require('webworker-threads').Worker;
let worker = new Worker(workerFunction);
// Run worker
return await new Promise(function(resolve, reject) {
worker.onmessage = function(e) { resolve(e.data); };
worker.postMessage(input, buffers);
});
}
You can get real-data from the objectURL and not just blob by changing the responseType
to either "text"
or "arraybuffer"
.
Here is a back-and-forth conversion of text/javascript
to blob
to objectURL
back to blob
or text/javascript
.
if you are wondering, I'm using it to generate a web-worker with no external files
you may use it to return binary content, for example a YouTube video ;) (from the <video> tag resource attribute)
var blob = new Blob(['self.onmessage=function(e){postMessage(e)}'],{type: 'text/javascript'}); //->console: (object) Blob {size: 42, type: "text/javascript", slice: function}
var obju = URL.createObjectURL(js_blob); //->console: "blob:http%3A//stackoverflow.com/02e79c2b-025a-4293-be0f-f121dd57ccf7"
var xhr = new XMLHttpRequest();
xhr.open('GET', 'blob:http%3A//stackoverflow.com/02e79c2b-025a-4293-be0f-f121dd57ccf7', true);
xhr.responseType = 'text'; /* or "blob" */
xhr.onreadystatechange = function(){
if(xhr.DONE !== xhr.readyState) return;
console.log(xhr.response);
}
xhr.send();
/*
responseType "blob" ->console: (object) Blob {size: 42, type: "text/javascript", slice: function}
responseType "text" ->console: (text) 'self.onmessage=function(e){postMessage(e)}'
*/
Use my tiny plugin https://github.com/zevero/worker-create
var worker_url = Worker.create("self.postMessage('Example post from Worker');");
var worker = new Worker(worker_url);
But you may also give it a function.
참고URL : https://stackoverflow.com/questions/10343913/how-to-create-a-web-worker-from-a-string
'programing tip' 카테고리의 다른 글
ASP.NET CLR이 활성화되지 않음 (0) | 2020.10.19 |
---|---|
CSV 리더 (Python)의 "줄에 NULL 바이트 포함" (0) | 2020.10.19 |
배치-rmdir 명령에서 "디렉토리가 비어 있지 않습니다"가져 오기 (0) | 2020.10.19 |
pip 명령을 사용하여 requirements.txt에서 Python 패키지 업그레이드 (0) | 2020.10.19 |
쌓인 반투명 상자의 색상은 주문에 따라 다릅니 까? (0) | 2020.10.19 |