Use 进程打开 http://php.net/manual/en/function.proc-open.php异步运行进程。让节点尽快输出数据。无需等待节点完成即可读取此数据:
// foo.js
process.stdout.write(JSON.stringify({"foo":"bar"})+"\n");
// simulate cleanup
setTimeout(() => {}, 3000);
// foo.php
<?php
$io = [
0 => ['pipe', 'r'], // node's stdin
1 => ['pipe', 'w'], // node's stdout
2 => ['pipe', 'w'], // node's stderr
];
$proc = proc_open('node foo.js', $io, $pipes);
$nodeStdout = $pipes[1]; // our end of node's stdout
echo date('H:i:s '), fgets($nodeStdout);
proc_close($proc);
echo date('H:i:s '), "done\n";
示例输出:
$ php foo.php
14:59:03 {"foo":"bar"}
14:59:06 done
proc_close 将等待节点进程退出,但您可以推迟等待,直到完成 PHP 中的其他操作。
如果您不调用 proc_close,则可能会出现僵尸进程,具体取决于您的环境。Docker 和 PID 1 僵尸收割问题 https://blog.phusion.nl/2015/01/20/docker-and-the-pid-1-zombie-reaping-problem/包含一个很好的解释。很多时候都是指docker,因为这里是僵尸经常出现的地方,但是还是普遍适用的。
某些服务器 API 具有为客户端“隐形”运行代码的规定。例如,fcgi 有fastcgi_finish_request http://php.net/manual/en/function.fastcgi-finish-request.php,您可以在 proc_close 之前调用它。这样 HTTP 客户端就不会注意到等待时间。
如果您不能容忍最终等待节点,请考虑将节点事物改为 Web 服务,它独立于 PHP 进行管理。