URL.createObjectURL from ChromeWorker/WebWorker instead of ArrayBuffer transferring

My bootstrap.js communicates with a ChromeWorker, and then bootstrap.js communicates with a framescript.

I used to transfer data from ChromeWorker to the bootstrap.js using the transferrables technique on ArrayBuffer. However I cannot transfer to the framescript as it is in a different process.

So rather then: 1) Transfer from ChromeWorker to bootstrap 2) Send copy of it to Framescript via message manager

I am doing this now: 1) In ChromeWorker do URL.createObjectURL for the blob of that ArrayBuffer 2) Tell bootstrap.js the url 3) Bootstrap.js tells the framescript the object url

I was wondering your thoughts about this method. I like to avoid transferring copies of large data via messaging system. But I’m not sure of the perf differences so wanted to ask you.

Thanks

You’re still transferring the data from one process to another, now with a significant processing overhead. I would have thought it was faster just to transfer the ArrayBuffer directly, unless you want it as a URL object anyway. Although I’ve found that working with even “raw” ArrayBuffers, for example making structured clones of them, can be surprisingly slow. Binary strings are still radically faster if there is some way you can get your hands on one and do something sensible with it when you have it.

Perhaps your focus should be on how to make an inevitably slow process work smoothly in an asynchronous way. I’m assuming you’ve exhausted the possibilities for obtaining and processing the buffer in the same process.

1 Like

Thanks litho for always replying!

One of my use cases is:

  1. Download as arraybuffer an image
  2. Use some heavy javascript stuff (imagemagick worker) to modify the image
  3. Get arraybuffer of modified image
  4. Send this image to multiple framescripts. (because multiple framescrpipts need it, I exhausted the possibility for doing it within single process :frowning: )

Pre Firefox 45 creating a blob url in the worker, was working great. However, in Firefox 45 (e10s enabled), the blob url creating in the worker does not work in any of the other processes. I didnt expect this. But should I have expected this?

By binary string do you mean I should consider converting my ArrayBuffer into a Data URI? :slight_smile: Thanks for that insight on a binary string being faster to structured clone then an ArrayBuffer!

Do you think it would be a better idea to write the arraybuffer to disk from the worker, and then just send the File URI to all the framescripts?

Which bit broke? Creating the blob in the Chrome Worker? Or accessing it in a frame script? Can Chrome Workers not send messages to frame scripts directly? I guess they’d need XPCOM to do that?

I don’t think your new method really changes anything, other than converting your large amount of data from one format to another (and then back again?). You are still sending the data from one thread to another in the same process (should be able to transfer?), and then sending it to another process. I wouldn’t bother changing the format if it isn’t necessary. Writing to a file would almost certainly work but it is unlikely to be faster. You could try profiling, of course, if performance is an issue. Maybe your OS file caching is more efficient than Firefox’s handling of ArrayBuffer data. You do know that frame scripts can’t use file functions, although to some extent you can work round this with XMLHttpRequest if you already have a file URL.

If you already have an ArrayBuffer, converting it to a binary string wouldn’t make much sense. Depends what you need in the frame script though. A data URI is not a binary string. In fact it isn’t binary at all, that’s kind of the point. A data URI is a base64-encoded representation of a binary string, with data: on the front to make it look like a URI. It is a handy way to pass images around (eg. through http) without having to write them to a file.

1 Like

The part that doesn’t work anymore - I create a blob in Chromeworker. I keep it globally referenced so its not GC’ed. I then do URL.createObjectURL. I then send that string (the url) to framescript and it wont load that image. I type that blob url into a tab and it wont load the image, its werid. So The generated blob:null/28asvsfe383j thing doesn’t load for anything outside that worker.

Thanks for that post I learn a ton from your posts.

ChromeWorkers can send direclty to the framescript. However because multiple framescripts use it, I load the worker in my bootstrap.js and then send the needed info to all the framescripts and vice versa.

I can’t transfer between bootstrap.js and framescript, it has to be a clone/copy as you helped me realize in the past (different processes - was kind of stupid I didnt realize that haha).

Yeah I’m not sure man I’m so uncertain which is the best way to get large pieces of data from bootstrap/worker (i group these two because i can transfer data between them easily) and out of content process framescripts. I can’t profile to figure out the perf between sending copied/structured-clone between the two versus (writing to file then reading it into framescript).

In the framescript I need to load the image in a <img src="...">.

I think I see your problem. You’re just sending the blob URL to the content process? Not the whole blob? I don’t think that works, because the URL is just a handy reference to the blob. The string is useless outside of a context where that blob exists. Unlike a true data URL, which actually contains all the data (base 64 encoded).

Ah yeah. It used to work in Firefox 44 though.

Which method would you take?

  1. filesystem method
  • in worker, do modifications to image
  • worker writes to file
  • send to bootstrap.js file uri
  • send file uri to framescripts.
  • framescript loads file uri in
  1. transfer then structured clone method
  • in workder, do modifications to image
  • transfer arraybuffer to bootstrap.js
  • send structured clone to framescripts
  • framescript loads arraybuffer into