Can a file be saved directly from a web worker?

I have a browser-based application (without using a backend) that parses XML data in files, which average about 250 MB. The actual parsing and parsing takes place in a web worker who transfers the data to fragments of 64 KB using an instance FileReader, and all this is quite efficient.

I have a request from a client to expand this application so that it can generate a .zip file containing the original input file and analysis results, and allow the user to save this file on his local computer. Creating a zip file in memory with this content is not a problem. The problem is transferring large amounts of data from the web worker, which generates it back to the main stream of the browser so that it can be saved; Attempting to do this invariably raises a failure exception or memory exception. (I tried to pass the lines at once and the piece at a time, and I tried to use ArrayBufferas a portable object to avoid copying. All do not work the same).

Unfortunately, I do not know how to invoke a file save operation directly from a workflow. I know several ways to do this from the main browser thread, but all of them require either the ability to create DOM nodes (which workflows, of course, they cannot do), or use interfaces (for example, msSaveBlob, saveAs) that the browser does not seem to open work flow. I spent some time searching for opportunities on the Internet, but did not find anything useful; FileWriterSyncIt looked good, but only Chrome supports it, and I also need to configure IE and Firefox.

Is there a method that I forgot to save files directly from a web worker? If so, then what is it? Or am I just out of luck?

+4
1

tl;dr demo

. , . .

Blob :

// Some arbitrary binary data
const mydata = new Uint16Array([1,2,3,4,5]);
// mydata vs. mydata.buffer does not seem to make any difference
const blob = new Blob([mydata], {type: "octet/stream"});

URL , Blob, URL. , :

const url = URL.createObjectURL(blob);

URL-:

const link = document.createElement("a");
link.download = "data.bin";
link.href = e.data.link;
link.appendChild(new Text("Download data"));
link.addEventListener("click", function() {
    this.parentNode.removeChild(this);
    // remember to free the object url, but wait until the download is handled
    setTimeout(()=>{URL.revokeObjectURL(e.data.link);}, 500)
});
document.body.appendChild(link);

, click . , , .

, :

worker.js

// Some arbitrary binary data
const mydata = new Uint16Array([1,2,3,4,5]);

self.onmessage = function(e) {
  console.log("Message: ",e.data)
  switch(e.data.name) {
    case "make-download" : 
        const blob = new Blob([mydata.buffer], {type: "octet/stream"});
        const url = URL.createObjectURL(blob);
        self.postMessage({name:"download-link", link:url});
    break;
    default:
      console.error("Unknown message:", e.data.name);
  }
}

main.js

var worker = new Worker("worker.js");
worker.addEventListener("message", function(e) {
  switch(e.data.name) {
    case "download-link" : {
       if(e.data.error) {
          console.error("Download error: ", e.data.error);
       }
       else {
          const link = document.createElement("a");
          link.download = "data.bin";
          link.href = e.data.link;
          link.appendChild(new Text("Download data"));
          link.addEventListener("click", function() {
              this.parentNode.removeChild(this);
              // remember to free the object url, but wait until the download is handled
              setTimeout(()=>{URL.revokeObjectURL(e.data.link);}, 500)
          });
          document.body.appendChild(link);
       }
       break;
    }
  default:
    console.error("Unknown message:", e.data.name);
  }
});

function requestDownload() {
  worker.postMessage({name:"make-download"});
}

"" , HEX:

enter image description here

:)

0

All Articles