从gjs读取异步标准输出

时间:2015-10-31 12:19:50

标签: javascript asynchronous gnome gnome-shell-extensions gjs

我正在尝试从gjs运行命令并异步读取输出。

这是我的同步代码

let [res, pid, in_fd, out_fd, err_fd] = GLib.spawn_async_with_pipes(null,
                                                  ['/bin/ls'], null, 0, null);
let out_reader = new Gio.DataInputStream({
  base_stream: new Gio.UnixInputStream({fd: out_fd})
});
var out = out_reader.read_until("", null);
print(out);

这样可以正常工作,但如果我尝试以异步方式进行,则无法正常工作

let [res, pid, in_fd, out_fd, err_fd]  = GLib.spawn_async_with_pipes(null,
                                                   ['/bin/ls'], null, 0, null);
let out_reader = new Gio.DataInputStream({
  base_stream: new Gio.UnixInputStream({fd: out_fd})
});
function _SocketRead(source_object, res, user_data){
  print("hi");
  let length;
  let out = out_reader.read_upto_finish(asyncResult, length);
  print("out" + out);
  print("length" + length);
}
var out = out_reader.read_upto_async("",0, 0, null, _SocketRead, "");
while(true){
   i = 0;
}

根本没有调用回调

1 个答案:

答案 0 :(得分:2)

首先感谢你提出这个问题,我也有同样的基本问题,就是你的初始行"我试图从gjs运行命令并异步读取输出"而你的问题有我需要的细节来找到解决方案!

在您的示例代码中,主要问题是以下几行:

while(true){
   i = 0;
}

您正确地尝试在获得输出之前阻止程序终止,但此解决方案无法正常工作。

Javascript是单线程的,这意味着虽然计算可以在串行交错的意义上同时运行,但是并行运行两个Javascript计算。没有办法显式地产生线程,问题中的繁忙循环只是继续旋转,回调永远不会占用CPU时间。

您想要的是进入事件循环。如果您正在开发Gnome Shell扩展,那么您已经在一个扩展中运行,但如果您只是在运行带有Gjs的脚本,则需要显式启动它。我将使用Clutter,但其他一些事件循环也会这样做。以下代码段构成了一个完整的,有效的解决方案。

首先,让我们从导入所需的库开始:

const GLib = imports.gi.GLib;
const Gio = imports.gi.Gio;
const Clutter = imports.gi.Clutter;

然后从问题中添加产卵和文件描述符:

const [res, pid, in_fd, out_fd, err_fd] = GLib.spawn_async_with_pipes(null, ['/bin/ls'], null, 0, null);
const out_reader = new Gio.DataInputStream({
  base_stream: new Gio.UnixInputStream({fd: out_fd})
});

调用异步读取函数并给它一个回调(在下面定义,由于Javascript提升可用于此处):

out_reader.read_upto_async("", 0, 0, null, _SocketRead, "");

启动事件循环:

Clutter.init(null);
Clutter.main();

你的回调中有一些错误,所以这里有一个固定版本,一旦命令停止产生输出,它也会终止事件循环:

function _SocketRead(source_object, res){
  const [out, length] = out_reader.read_upto_finish(res);
  if (length > 0) {
    print("out: " + out);
    print("length: " + length);
    out_reader.read_upto_async("", 0, 0, null, _SocketRead, "");
  } else {
    Clutter.main_quit();
  } 
} 

为了进一步阅读,https://people.gnome.org/~gcampagna/docs有Gjs本地绑定文档。