文字列(POSTリクエストを介して提供されます)からWebワーカーを作成するにはどうすればよいですか?
私が考えることができる1つの方法は、それを実装する方法がわからない、サーバー応答からデータURIを作成し、それをWorkerコンストラクタに渡すことですが、一部のブラウザでは許可されていないと聞いていますこれは、同じOriginポリシーのためです。
MDNは、データURIに関するOriginポリシーについての不確実性を述べています :
注:Workerコンストラクターのパラメーターとして渡されるURIは、same-Originポリシーに従う必要があります。現在、ブラウザーのベンダー間では、データURIが同じ起源であるかどうかについて意見の相違があります。 Gecko 10.0(Firefox 10.0/Thunderbird 10.0)以降では、データURIをワーカーの有効なスクリプトとして許可しています。他のブラウザは同意しない場合があります。
こちらも投稿です whatwgで議論します 。
概要
- _
blob:
_ for Chrome 8 +、Firefox 6 +、Safari 6.0 +、Opera 15+- _
data:application/javascript
_ for Opera 10.60-12eval
それ以外(IE 10+)
URL.createObjectURL(<Blob blob>)
を使用して、文字列からWebワーカーを作成できます。ブロブは BlobBuilder
APIを使用して作成できます 非推奨 または 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');
_
Webワーカーは次のブラウザーでサポートされています ソース:
このメソッドのサポートは、Blob
APIおよび_URL.createObjectUrl
_メソッドのサポートに基づいています。 Blob
互換性 :
WebKitBlobBuilder
)、20+(Blob
コンストラクター)MozBlobBuilder
)、13+(Blob
コンストラクター)Blob
コンストラクター)IE10はMSBlobBuilder
および_URL.createObjectURL
_をサポートしています。ただし、_blob:
_-- URLからWeb Workerを作成しようとすると、SecurityErrorがスローされます。
Opera 12はURL
APIをサポートしていません。 _browser.js
_ のこのハックのおかげで、一部のユーザーはURL
オブジェクトの偽バージョンを持っている場合があります。
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/
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でテストされています
私はあなたのアイデアのほとんどを使ってアプローチし、私のアイデアを追加しました。私のコードでワーカーに必要なのは、「this」を使用して「self」スコープを参照することだけです。これは非常に改善可能であると確信しています。
// 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');
}
@Chanu_Sukarnoのコードを展開すると、この関数にワーカー関数(または文字列)を渡すだけで、Webワーカー内で実行されます。
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);
});
}
以下に使用方法の例を示します。
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")
nodejsでは、doWorkerTask
は次のようになります。
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);
});
}
いい答え-今日は、フォールバック機能を使用できないWebワーカーを作成しようとするとき(メインスレッドでワーカースクリプトを実行するなど)、同様の問題に取り組んでいます。このスレッドはトピックに関連しているため、ここで解決策を提供すると思いました。
<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 [email protected] 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.jsCPUを集中的に使用するコードをすべてのコア(node.jsおよびweb)で実行するための簡素化されたインターフェース
例は
// 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
});
responseType
を"text"
または"arraybuffer"
に変更することで、blobだけでなくobjectURLから実データを取得できます。
前後の変換 of text/javascript
to blob
to objectURL
back to blob
or text/javascript
。
あなたが疑問に思っているなら、私はそれを使用して外部ファイルのないウェブワーカーを生成しています
YouTubeビデオなどのバイナリコンテンツを返すために使用できます;)(<video>タグリソース属性から)
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)}'
*/