2015-10-31 11 views
1

Я пытаюсь запустить команду из gjs и читать выход асинхронно.читать asynchronous stdout из 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; 
} 

обратного вызова не вызывается на всех

ответ

2

Прежде всего, спасибо за этот вопрос, у меня также был тот же основной вопрос, то есть ваша начальная строка «Я пытаюсь запустить команду из gjs и читать асинхронный вывод» и ваш квест у Иона были детали, которые мне нужны, чтобы найти решение!

В вашем примере коде, главная проблема заключается в этих строках:

while(true){ 
    i = 0; 
} 

Вы правильно пытаетесь сохранить программу от завершения, прежде чем получить результат, но это решение не работает.

Javascript является однопоточным, что означает, что, хотя вычисления могут выполняться одновременно в последовательном чередовании, не может быть двух параллельных вычислений Javascript. Невозможно явно передать поток, и цикл занятости в вопросе просто продолжает вращаться, и обратный вызов никогда не получает процессорное время.

Вместо этого вы должны ввести цикл событий. Если вы разрабатываете расширение 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 hoisting):

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(); 
    } 
} 

Для Дальнейшее чтение содержит документы привязки Gjs на уровне https://people.gnome.org/~gcampagna/docs.