📜 ⬆️ ⬇️

We cross WebWorker and Promise

If there is a need to cross WebWorker with XMLHttpRequest , then it is time to cross it with any function, and at the same time deal with the promises of ES6 .

The goal is to learn to do this:
new PromiseWorker(array => array.sort()).Invoke([3,2,1]).then(result => console.log(result));
(The arrow functions for brevity are hereinafter used).


')
As you know, the true way to create a worker is to pass the path to the file as the only parameter: new Worker("/JS/worker.js") . hang the onmessage handler, call postmessage and stick to the same style in the worker file. In my opinion, it’s too bold to create a whole file for one function, and it’s no longer comfy to deal with event handlers. Good thing there are Blob and Promises already mentioned.

First, you need to make the conversion of the input function to the form acceptable for the worker:
 var FnToWorker = fn => { var workerBody = "self.addEventListener('message'," + "function (d) {" + "var result;" + "try {" + "result = (" + fn.toString() + ")(d.data.Data);" + "self.postMessage({ Result: result, Id: d.data.Id });" + "} catch (e) {" + "self.postMessage({ Error: e, Id: d.data.Id });" + "}" + "});" var worker = new Worker(URL.createObjectURL(new Blob([workerBody]))); return worker; } 

Yes, there is a disgusting concatenation of strings, fn.toString () and other terrible things ... the main thing is that you can write this code and forget about it once.
As pointed out in the comments, this construction imposes some restrictions: the function must not have external dependencies (variable closures, window objects that are not allowed for the workers), since they will not be accessed from the worker thread. Functions created using system functions (for example, Function.prototype.bind) cannot be used in workers because fn.toString () does not return the body of the function.

This is how Invoke will look like:
 var promises = []; //  var Invoke = data => { var message = { Data: data, Id: performance.now() }; //   Id,     var p = new Promise((resolve, reject) => { promises[message.Id] = { resolve: resolve, reject: reject }; }); worker.postMessage(message); //  return p; } 

Using Promise is not difficult: we pass a function from the two arguments to the constructor: resolve and reject. These are functions that should be called in case of success of the operation and failure, respectively. In our case, they will be called after the worker has completed:
 var OnMessage = data => { if (data.data.Error) { promises[data.data.Id].reject(data.data.Result); } else { promises[data.data.Id].resolve(data.data.Result); } promises[data.data.Id] = undefined; } 


Well, here it will look like in the collection: http://jsfiddle.net/sXJ4M/1/

Of course, it’s hard to imagine where you can use the workers in an online store, but they help a lot in fairly large and complex applications.

Source: https://habr.com/ru/post/219037/


All Articles