Как я могу использовать создание веб-воркера из строки (которая предоставляется через запрос POST)?
Один из способов, который я могу придумать, но я не уверен, как его реализовать, - это создать URI данных из ответа сервера и передать его конструктору Worker, но я слышал, что некоторые браузеры не позволяют это из-за той же политики происхождения.
MDN заявляет о неопределенности политики происхождения в отношении URI данных :
Примечание: URI, переданный как параметр конструктора Worker, должен подчиняться политике того же происхождения. В настоящее время производители браузеров расходятся во мнениях относительно того, имеют ли URI данные одного происхождения или нет; Gecko 10.0 (Firefox 10.0 / Thunderbird 10.0) и более поздние версии позволяют использовать URI данных в качестве допустимого сценария для рабочих. Другие браузеры могут не согласиться.
Здесь также обсуждается это сообщение на whatwg .
источник
Ответы:
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');
Совместимость
Веб-воркеры поддерживаются в следующих исходных браузерах :
Поддержка этого метода основана на поддержке
Blob
API иURL.createObjectUrl
метода.Blob
совместимость :WebKitBlobBuilder
), 20+ (Blob
конструктор)MozBlobBuilder
), 13+ (Blob
конструктор)Blob
конструктор)IE10 поддерживает
MSBlobBuilder
иURL.createObjectURL
. Однако попытка создать Web Worker изblob:
-URL вызывает ошибку SecurityError.Opera 12 не поддерживает
URL
API. У некоторых пользователей может быть поддельная версияURL
объекта благодаря этому взломуbrowser.js
.Резерв 1: data-URI
Opera поддерживает URI данных в качестве аргумента
Worker
конструктора. Примечание. Не забывайте экранировать специальные символы (например,#
и%
).// 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
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
источник
MSBlobBuilder
иURL.createObjectURL
. Однако при попытке создать Web Worker изblob:
-URL выдается SecurityError.». Таким образом, добавление неMSBlobBuilder
будет иметь никакого эффекта, единственный вариант - резерв №2.URL
(и, следовательно, не определяет никаких свойств), а конструктор Blob в настоящее время достаточно хорошо поддерживается.data:
-URI для веб-воркеров также поддерживаются в Firefox, но не в Chrome или Opera 15+. Производительностьeval
не имеет значения, вы не собираетесь создавать миллионы веб-воркеров в секунду.Я согласен с текущим принятым ответом, но часто редактирование и управление рабочим кодом будет беспокойным, поскольку он имеет форму строки.
Так что при желании мы можем использовать нижеприведенный подход, в котором мы можем сохранить работника как функцию, а затем скрыть его до 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.
источник
Я применил большинство ваших идей и добавил некоторые свои. Единственное, что моему коду нужно в worker, - это использовать 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'); }
Демо: http://jsfiddle.net/8N6aR/
источник
Принятый ответ немного сложен из-за поддержки обратной совместимости, поэтому я хотел опубликовать то же самое, но в упрощенном виде. Попробуйте это в (современной) консоли браузера:
const code = "console.log('Hello from web worker!')" const blob = new Blob([code], {type: 'application/javascript'}) const worker = new Worker(URL.createObjectURL(blob)) // See the output in your console.
источник
Хороший ответ - сегодня я работал над аналогичной проблемой, пытаясь создать веб-воркеров с резервными возможностями, когда они недоступны (например, запустить рабочий скрипт в основном потоке). Поскольку эта ветка относится к теме, я подумал, что предоставлю здесь свое решение:
<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>
источник
В зависимости от вашего варианта использования вы можете использовать что-то вроде
Примером может быть
// 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
.если вам интересно, я использую его для создания веб-воркера без внешних файлов,
вы можете использовать его для возврата двоичного контента, например видео 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)}' */
источник
Используйте мой крошечный плагин https://github.com/zevero/worker-create
var worker_url = Worker.create("self.postMessage('Example post from Worker');"); var worker = new Worker(worker_url);
Но вы также можете дать ему функцию.
источник