Как создать веб-работника из строки
Как я могу использовать создать веб-работника из строки (которая поставляется через запрос POST)?
один из способов, о котором я могу думать, но я не уверен, как его реализовать,-это создать URI данных из ответа сервера и передать его в конструктор Worker, но я слышал, что некоторые браузеры не позволяют этого из-за той же политики происхождения.
MDN указывает на неопределенность политики происхождения вокруг URI данных:
Примечание.: URI, переданный как параметр рабочего конструктора, должен подчиняться политике того же источника. В настоящее время среди поставщиков браузеров существуют разногласия по поводу того, имеют ли URI данных одно и то же происхождение или нет; Gecko 10.0 (Firefox 10.0 / Thunderbird 10.0) и позже разрешают URI данных в качестве допустимого сценария для рабочих. Другие браузеры могут не согласиться.
вот еще пост обсуждаем это на whatwg.
8 ответов:
резюме
blob:
для Chrome 8+, Firefox 6+, Safari 6.0+, Opera 15+data:application/javascript
для оперы 10.60 - 12eval
в противном случае (т. е. 10+)
URL.createObjectURL(<Blob blob>)
может использоваться для создания веб-работника из строки. Большой двоичный объект может быть создан с помощью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');
совместимость
веб-работники поддерживаются в следующих браузерах источник:
- Chrome 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 выдает SecurityError.Opera 12 не поддерживает
URL
API. Некоторые пользователи могут иметь поддельные версии
Я согласен с текущим принятым ответом, но часто редактирование и управление рабочим кодом будет беспокойным, как и его в виде строки.
поэтому дополнительно мы можем использовать следующий подход, где мы можем сохранить работника в качестве функции, а затем скрытый в строку - > 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
Я сделал подход с большинством ваших идей и добавив некоторые из моих. Единственное, что нужно моему коду на worker, это использовать "это" для ссылки на область "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'); }
хороший ответ-я работал над аналогичной проблемой сегодня при попытке создать веб-работников с резервными возможностями, когда они недоступны (т. е. запустить рабочий скрипт в главном потоке). Поскольку эта тема относится к теме, я думал, что предоставлю свое решение здесь:
<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>
в зависимости от вашего варианта использования вы можете использовать что-то вроде
задач.js упрощенный интерфейс для получения интенсивного кода процессора для работы на всех ядрах (узел.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 });
расширяя код @Chanu_Sukarno, вы можете просто передать рабочую функцию (или строку) этой функции, и она выполнит ее внутри веб-работника:
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); }); }
вы можете получить данные из objectURL и не просто blob, изменив
responseType
или"text"
или"arraybuffer"
.здесь туда и обратно преобразования на
text/javascript
доblob
доobjectURL
наblob
илиtext/javascript
.если вам интересно, я использую его для создания web-worker без внешних файлов
вы можете использовать его для возврата двоичного содержимого, например видео YouTube;) (из атрибута ресурса тега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)}' */
используйте мой крошечный плагин https://github.com/zevero/worker-create
var worker_url = Worker.create("self.postMessage('Example post from Worker');"); var worker = new Worker(worker_url);
но вы также можете дать его функция.