12

So I am working on a project in Node.js and I want to open up some extra threads to handle the processing load more efficiently. But I am using classes with function definitions with them and when I try to send those objects to the worker thread, the functions defined in the object disappear and I am only left with the other fields in the object. Is there a way to send the worker an object and preserve the functions so they can be called within the worker?

var cluster = require('cluster');

if(cluster.isMaster){
    Monster = function(species){
        this.attack = function(){
            console.log('CHOMP');
        };
        this.name = species;
    };
    var vamp = new Monster('vampire'),
    worker   = cluster.fork();
    worker.send({'monster' : vamp});
    }
else{
    process.on('message', function(msg) {
        console.log(msg.monster); //this logs "{ name: 'vampire' }"  
        msg.monster.attack(); //TypeError: Object #<Object> has no method 'attack'
    });
}
1
  • 1
    Perplexed: the title and text of your question are interesting and make sense for me, to date in 2021. But the code example is unrelated/obsolete, because it shows how to use nodejs cluster of PROCESSES instead of of nodejs WORKER THREADS. Even if I realize that in 2012 nodejs didn't contain worker threads. Commented Apr 26, 2021 at 20:11

3 Answers 3

9

No, there is no way to pass functions between threads. You can pass only JS plain objects (data only) and handle it with functions defined in current thread (like create new object with received data).

Sign up to request clarification or add additional context in comments.

3 Comments

wow that really limits the functionality of the cluster module. Do you know if there are any plans to add that to Node.js?
This functionality is contrary to node.js architecture. Node.js event-loop works in single thread. Cluster module just starts new processes. They all have their own independent memory. Implementation of multi-threaded architectures need to support threads with shared memory and related mechanisms such as mutexes and semaphores. This is not node.js way.
Upvoted. See details about why functions can not be shared between threads: 1. nodejs.org/api/… and 2. developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/…
3

Charlie, I realize you asked this question a year ago, but I was wanting to do something very similar and I came across your question which you didn't mark an answer to yet. I thought I would take a "stab" at it and show you what I have done with your code. This different way of organizing code is for me a very acceptable workaround in my node.js work. I am pretty sure this gives you a way to accomplish what you want, even though you can't do it in the manner you wanted.

Declare your "class" outside the cluster code, like this:

var cluster = require('cluster');

var Monster = function(species){
    this.attack = function(){
        console.log('CHOMP!');
    };
    this.die = function() {
        console.log("Oh, what did I eat?  I don't feel so good....\r\n");
        process.exit(0);
    };
    this.scare = function() {
        console.log("BOO! I am a " + this.name + "!");
    };
    this.name = species;
};

if(cluster.isMaster){
    worker = cluster.fork();
    worker.send({'species' : 'Vampire'});
}
else{
    process.on('message', function(msg) {
        if(typeof msg.species !== "undefined") {
            myMonster = new Monster(msg.species);
            myMonster.scare();
            myMonster.attack();
            myMonster.die();
        }
    });
}

Give that a whirl and see if this is an answer you can accept!

1 Comment

Smart solution/maybe the only feasible. But in your code there is no sharing of an "object with functions to worker thread", as the title of the question states. There are no worker threads, you just fork a cluster of processes where each process create his own object(s). Nice but the "worst case" option, not suitable if you want to share big data object(s) and/or containg functions (references).
1

Ok, stumbled upon this answer, and I found it strange that no one brought this up, but it might be a more modern feature than the question:

eval

let str = "() => { console.log('test') }"
let func = eval(str)
func()

Think it's obvious what's going on here, you can parse any string to javascript, and you can send strings to workers, so you can build and object with functions:

let obj = { a: "() => { ... }" }

and send the object over. (JSON.stringify(obj) first, and than you will have to parse the object first, and than all the substrings seperately)

4 Comments

This is potentially dangerous, especially on a Node server which has access to other parts of the system. Imagine someone uploads a file named return (function () { /* arbitrary code*/ })();, and in your class, and somehow that file name ends up getting passed to eval instead of your function. It's unlikely, but using eval in server code just opens up more vulnerabilities to your system.
I completely agree if you are going to evaluate a request. However, in the case of the OP, he's sending his own code over to the worker, so 'eval' is honestly the best solution IMO.
'eval' is honestly the best solution, unless you knew you could just serialise functions. Honestly, if the function in question isn't the one doing the compute, wrapping it up as a callback listening for its own personalised postMessage is actually the best solution (with the added bonus that any closures and class instances continue to work; because they never left the originating thread)
Genius! Can't believe I never thought of such an approach.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.