0

The question is formalized as this.

Can we call a non-pure function in another thread in javascript and get a Promise?

One possible implementation of this feature is.

function executeAsync(f: function, ...args);

1. Javascript runtime spawns 1 parallel unit (thread, coroutine, etc).

2. Javascript runtime executes the function f in parallel. (Ignore data race issue, maybe add mutex later)

3. After the parallel unit has done its job. Remove the parallel unit from the pool and resolve the Promise. (put callback into the callback queue)

Please comment if you still have any doubt. Thanks

FOR REFERENCES

The code below I implemented serves the similar purpose but it doesn't work for non-pure function It uses safe-eval node module that evaluates a string and convert to javascript function

const {isMainThread, Worker, workerData, parentPort} = require("worker_threads");
const {safeEval} = require("safe-eval");
if (isMainThread) {
  // functionObject must be pure function
  module.exports = {executeAsync: function(functionObject = function(...paramsObject) {return undefined;}, ...paramsObject) {
    return new Promise(function(resolve, reject) {
      const worker = new Worker(__filename, {
        workerData: {
          functionString: functionObject.toString(),
          argumentsObject: paramsObject,
        }
      });
      worker.on("message", resolve);
      worker.on("error", reject);
      worker.on("exit", function(functionObject) {
        if (functionObject != 0) {
          reject(new Error(`Worker stopped with code ${functionObject}`));
        }
      });
    });
  }};
} else {
  const {functionString, argumentsObject} = workerData;
  const functionObject = safeEval(functionString);
  parentPort.postMessage(functionObject(...argumentsObject));
}
khanh
  • 600
  • 5
  • 20

1 Answers1

1

One particular approach to this in JavaScript is putting the function into a executeAsync function, it returns a promise for us to access it later.

This is a common misconception. Promises don't make something that's synchronous asynchronous. They're just a standardized way to observe something that's already asynchronous. The only asynchronous behavior they themselves provide is that when you register a handler via .then (or .catch or .finally), you're guaranteed that that handler will be called asynchronously, not synchronously, even if the promise is already settled. And even then, it's asynchronous, not parallel. The callback happens on the same thread, just later.

The only way¹ to get truly parallel processing in browser-based JavaScript is to use web workers, which Node.js's workers are modelled on. As you've said, that mostly means you have to have a separate file for the code that will run in the worker, although it is possible to use a string.


¹ "only way" - well, technically separate independent tabs may end up running in different threads, but only if they are created completely independently. If one tab opens another, they'll share the same thread, since they each have a reference to the other.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • Thanks for the answer. The first part does not directly target the question. "The only way¹ to get truly parallel processing in browser-based JavaScript is to use web workers" - thanks – khanh Oct 06 '19 at 10:56
  • @NgọcKhánhNguyễn - No, the first part targets a common misconception expressed in the question, as I said above. – T.J. Crowder Oct 06 '19 at 11:00
  • Thanks, it might be due to ambiguity I made in the question – khanh Oct 06 '19 at 11:02