如何从字符串创建子进程

时间:2017-07-14 15:41:15

标签: javascript node.js

在浏览器中,我们可以使用javascript字符串创建worker,如下所示:

$(".left-col-content > .content").append(() => {
  return "left-col<br>".repeat(350);
});
$(".right-col-content > .content").append(() => {
  return "right-col<br>".repeat(350);
});
$(".terminal-row > .content").append(() => {
  return "terminal<br>".repeat(350);
});

$(".body-col-content > .content").append(() => {
  return "content<br>".repeat(350);  
});

$(".body-col-header > .content").append(() => {

  left_btn = $("<button>Toggle Left</button>").click(() => {
    $(".left-col").toggle();
    $(".body-col").toggleClass("left-hidden");
  });

  right_btn = $("<button>Toggle Right</button>").click(() => {
    $(".right-col").toggle();
    $(".body-col").toggleClass("right-hidden");
  });

  terminal_btn = $("<button>Toggle Terminal</button>").click(() => {
    $(".terminal-row").toggle();
    $(".main-row").toggleClass("terminal-hidden");
  });


  buttons = $("<div></div>")
    .append(left_btn)
    .append(right_btn)
    .append(terminal_btn);

  return buttons;

});

有没有办法用节点的child process做到这一点?我有一个JavaScript文件,我想创建动态编码的工作程序。

源字符串是在运行时动态创建的。

我找到的最接近的答案是this one,但它需要一个单独的文件。

2 个答案:

答案 0 :(得分:10)

如果我理解正确的话,我创建了a module,它就是昨天做的。

它不打算从字符串创建worker,而是从实际函数创建,因为实际的函数代码必须通过思想消息传递,它们被字符串化以在工作者中重建(思考eval())。

这是在代码中完成的:

var source = fn.toString();

...所以,拥有该字符串原型也有一个.toString()方法,将函数作为字符串传递也必须工作(事实上是有效的。我只是测试了它。)

可能不是您想要的:如果您需要向工作人员传递和传递消息,则此模块不适合您。但是你可以看到the code并修改它以满足你的需要。

另一方面,如果你只想在后台执行某些函数并获得结果,那么它比处理工作线程更简单,因为你可以将函数传入函数并获得结果就像一个简单的函数调用

示例:

// Reauires funwork (`npm install --save funwork`)

var funwork = require("funwork");
var workerfn = funwork(function_src_string); // or actual function.

它的缺点是必须通过eval()来评估函数,但在你的情况下,(有一个字符串源代码)我觉得这绝对是必须的。

编辑:以下是 funwork 的修改版本,可以在评论中讨论您想要的内容:

var Worker = require('webworker-threads').Worker;
var Deasync = require('deasync');

function strWorker(fn){

    var source = fn.toString();

    return function() {

        var done = false;
        var args = Array.prototype.slice.call(arguments);
        var error;

        // Create worker://{{{
        var worker = new Worker(function(){
            var fn;
            var me = this;

            // Wait for function source and arguments:
            me.onmessage = function(event) {
                switch (event.data.oper) {
                    case "src":
                        // "Compile" function thougt source evaluation.
                        try {
                            eval ("fn = " + event.data.msg + ";");
                            postMessage(['ready']);
                        } catch (e) {
                            postMessage(['error', "Error trying to evaluate function source"]);
                        };
                        break;
                    case "args":
                        // Call the function with given arguments and reset the rest of worker stuff.
                        try {
                            // Reset worker (inside) event handler:
                            delete me.onmessage;

                            // Notify that worker is ready:
                            postMessage(["ok"]);

                            // Start function execution:
                            fn.apply(me, event.data.msg);

                        } catch (e) {
                            postMessage(['error', e]);
                        };
                        break;
                };
            };
        });//}}}

        // Event handling://{{{
        worker.onmessage = function(event) {
            switch (event.data[0]) {
                case 'error':
                    worker.postMessage({oper: "end"});
                    done = true;
                    error = event.data[1];
                    break;
                case 'ready':
                    worker.postMessage({oper: "args", msg: args});
                    break;
                case 'ok':
                    done = true;
                    break;
            };
        };//}}}

        // Send function source to worker:
        worker.postMessage({oper: "src", msg: source});

        // Wait (without blocking) until worker executed passed function:
        Deasync.loopWhile(function(){return !done;});

        if (error) throw error;

        // Reset worker (outside) event handler:
        delete worker.onmessage;

        return worker;
    };

};

module.exports = strWorker;

我保留了将参数传递给函数的能力,因为它已经实现了,如果你不需要传递任何东西,你就可以不使用它。

用法与生成的函数返回正在运行的worker而不是函数返回值的唯一区别相同。

使用的事件处理程序(worker内部和外部)分别在函数(作为字符串传入)执行和worker返回之前被删除,以避免任何副作用和执行上下文(&#34; this&#34;)传入函数的设置也设置为实际的工作者&#34; parent&#34;功能。

答案 1 :(得分:2)

如果您希望单个文件js启动不同的进程,则创建群集可能是一种解决方案。这是一个非常好的教程:Tutorial

基本上节点带有本机群集模块

var cluster = require('cluster');

您可以通过 cluster.isMaster 判断该进程是主进程还是工作进程。如果进程是主进程,则可以通过执行 cluster.fork()

来启动工作程序
if (cluster.isMaster) {
    for (var i = 0; i < numCPUs; i++) {
        cluster.fork();
    }
} else {
    http.createServer(function(req, res) {
        res.writeHead(200);
        res.end('process ' + process.pid + ' says hello!');
    }).listen(8000);
}

希望这有帮助。

对于子进程,您可以 child_process.fork(modulePath [,args] [,options])来运行其他模块并传入参数。模块可以根据参数执行不同的操作,因此它是动态的...似乎您只需要基于输入的动态行为,如果您可以将代码放在不同的文件中,则child_process可以执行此操作。如果只能有一个,请尝试使用群集解决方案。