How to create a Web Worker from a string
Summary
blob:
for Chrome 8+, Firefox 6+, Safari 6.0+, Opera 15+data:application/javascript
for Opera 10.60 - 12eval
otherwise (IE 10+)
URL.createObjectURL(<Blob blob>)
can be used to create a Web worker from a string. The blob can be created using the BlobBuilder
API deprecated or the Blob
constructor.
Demo: 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');
Compatibility
Web workers are supported in the following browsers source:
- Chrome 3
- Firefox 3.5
- IE 10
- Opera 10.60
- Safari 4
This method's support is based on the support of the Blob
API and the URL.createObjectUrl
method. Blob
compatibility:
- Chrome 8+ (
WebKitBlobBuilder
), 20+ (Blob
constructor) - Firefox 6+ (
MozBlobBuilder
), 13+ (Blob
constructor) - Safari 6+ (
Blob
constructor)
IE10 supports MSBlobBuilder
and URL.createObjectURL
. However, trying to create a Web Worker from a blob:
-URL throws a SecurityError.
Opera 12 does not support URL
API. Some users may have a fake version of the URL
object, thanks to this hack in browser.js
.
Fallback 1: data-URI
Opera supports data-URIs as an argument to the Worker
constructor. Note: Do not forget to escape special characters (Such as #
and %
).
// response as defined in the first example
var worker = new Worker('data:application/javascript,' +
encodeURIComponent(response) );
// ... Test as defined in the first example
Demo: http://jsfiddle.net/uqcFM/37/
Fallback 2: Eval
eval
can be used as a fallback for Safari (<6) and 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
Web workers without a separate Javascript file?
http://www.html5rocks.com/en/tutorials/workers/basics/#toc-inlineworkers
What if you want to create your worker script on the fly, or create a self-contained page without having to create separate worker files? With Blob(), you can "inline" your worker in the same HTML file as your main logic by creating a URL handle to the worker code as a string
Full example of BLOB inline worker:
<!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>
How can I load a shared web worker with a user-script?
You can use fetch()
, response.blob()
to create an Blob URL
of type application/javascript
from returned Blob
; set SharedWorker()
parameter to Blob URL
created by URL.createObjectURL()
; utilize window.open()
, load
event of newly opened window
to define same SharedWorker
previously defined at original window
, attach message
event to original SharedWorker
at newly opened window
s.
javascript
was tried at console
at How to clear the contents of an iFrame from another iFrame, where current Question URL should be loaded at new tab
with message
from opening window
through worker.port.postMessage()
event handler logged at console
.
Opening window
should also log message
event when posted from newly opened window
using worker.postMessage(/* message */)
, similarly at opening window
window.worker = void 0, window.so = void 0;
fetch("https://cdn.rawgit.com/viziionary/Nacho-Bot/master/webworker.js")
.then(response => response.blob())
.then(script => {
console.log(script);
var url = URL.createObjectURL(script);
window.worker = new SharedWorker(url);
console.log(worker);
worker.port.addEventListener("message", (e) => console.log(e.data));
worker.port.start();
window.so = window.open("https://stackoverflow.com/questions/"
+ "38810002/"
+ "how-can-i-load-a-shared-web-worker-"
+ "with-a-user-script", "_blank");
so.addEventListener("load", () => {
so.worker = worker;
so.console.log(so.worker);
so.worker.port.addEventListener("message", (e) => so.console.log(e.data));
so.worker.port.start();
so.worker.port.postMessage("hi from " + so.location.href);
});
so.addEventListener("load", () => {
worker.port.postMessage("hello from " + location.href)
})
});
At console
at either tab
you can then use, e.g.; at How to clear the contents of an iFrame from another iFrame worker.postMessage("hello, again")
at new window
of current URL How can I load a shared web worker with a user-script?, worker.port.postMessage("hi, again");
where message
events attached at each window
, communication between the two window
s can be achieved using original SharedWorker
created at initial URL.
Is there a way to render an SVG string to an OffscreenCanvas in a web worker?
No native way yet.
Per the specs, you should be able to create an ImageBitmap from a Blob holding your SVG image even in a Worker.
In reality, no browser has implemented it, and when I talked about it with the implementers, it seems it's not on anyone's track to do so.
In Chrome you have access to the Path2D constructor, which can somehow help with <path>
's d
attributes, but that's really just a very small part of rendering an SVG.
So the best will probably be to use a library for this.
Notabily, I think canvg is the most appropriate here. I don't use it myself but they're here for a long time now, and it seems the latest version does work with OffscreenCanvas in a Worker (in Chrome).
Create a Web Worker from a Chrome Extension content script
http://crbug.com/357664 is the bug report about not being able to load extension scripts as a web worker.
The workaround to this problem is to load the worker script using XMLHttpRequest, then load the worker from a string. When I faced this problem in the past, I created a wrapper that transparently modifies the Worker
constructor, so you can use new Worker(chrome.runtime.getURL('worker.js'))
without any problems.
See patch-worker.js
(documentation) for the implementation of the previous idea.
patch-worker.js
has some limitations (e.g. importScripts
does not work as expected), mainly related to the fact that it does not run in the chrome-extension:
-origin. To solve these problems, I created another library that uses an iframe to create the Worker. See worker_proxy
for the source code and documentation.
Make a function run via web workers
You can inline a web worker as a blob without using a separate file:
<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" });
var worker = new Worker(window.URL.createObjectURL(blob));
worker.onmessage = function(e) {
console.log("Received: " + e.data);
}
worker.postMessage("hello");
// Start the worker
</script>
Note that browser support might not be as robust with this method.
See here for additional details: https://stackoverflow.com/a/6454685/5535081
plainToClass to call object.method() in web worker thread
Passing data to a Web worker is done by serializing the object, so you won't be able to pass in behavior. Instead, you'll need to either use plainToClass
as you have in your example, or you can provide the functionality in a helper function.
Additionally, import reflect-metadata
is an import for side-effects. This code is run once per context, so it will need to be run again inside the worker, and then plainToClass
should work.
That said, a simpler approach might be to try to call the class constructor using the values passed in - if that’s possible?
Related Topics
Proper Use of Const for Defining Functions
React.Js: Onchange Event for Contenteditable
Why Use Object.Prototype.Hasownproperty.Call(Myobj, Prop) Instead of Myobj.Hasownproperty(Prop)
React - Preventing Form Submission
In JavaScript, How to Check If an Array Has Duplicate Values
Check If Jquery Has Been Loaded, Then Load It If False
Setting Multiple Attributes for an Element at Once with JavaScript
How to Stop a Page from Unloading (Navigating Away) in Js
Using a Variable in Mongodb Update
Eslint Parsing Error: Unexpected Token
How to Clone a JavaScript Object Except for One Key
JavaScript Regular Expressions and Sub-Matches
How to Calculate the Latlng of a Point a Certain Distance Away from Another
How to Copy JavaScript Object to New Variable Not by Reference
Updating and Merging State Object Using React Usestate() Hook
JavaScript Getelementbyid() Not Working