Есть ли синхронный для jq? - PullRequest
0 голосов
/ 06 июня 2019

jq.run('.', '/path/to/file.json').then(console.log) является асинхронным, поэтому, когда я пытаюсь использовать его, я получаю это: Promise { <pending> } И ТОГДА я получаю результат, но уже слишком поздно ... так как я могу это исправить? Я пытаюсь подождать с await, но я не знаю, где я могу поставить это ключевое слово. Итак, вот мой код:

const jq = require('node-jq')
const filter = '[.root[].A[].AT]'
const jsonPath = './simple.json'

 data = jq.run(filter, jsonPath).then((output) => {
    console.log(output)
  }).catch((err) => {
    console.error(err)
  })

fs.appendFile('./jqTest.txt', data + "\r\n", function (err) {
  if (err) throw err;
  console.log("complete!")
});

1 Ответ

1 голос
/ 06 июня 2019

Весь смысл асинхронных API в том, что вы не можете писать

data = getResultsAsynchronously();
doStuffWith(data);
...

(Если вы не используете await, что немного волшебно.)

Вместо этого традиционные асинхронные API-интерфейсы принимают функцию для вызова, когда результат готов:

getResultsAsynchronously(function (data) {
    doStuffWith(data);
    ...
});

т.е. весь код, который следует за исходным вызовом функции в синхронной версии, вместо этого помещается в функцию обратного вызова и передается в getResultsAsynchronously.

Обещания по-прежнему следуют этому общему шаблону, но позволяют отделить, начиная саму асинхронную операцию, от решения, как обрабатывать результат. То есть вы можете сначала запустить асинхронную операцию и зарегистрировать обратный вызов, который обрабатывает результаты позже, на втором шаге:

promise = getResultsAsynchronously();
// and later:
promise.then(function (data) {
    doStuffWith(data);
    ...
});

Однако вам не нужно разделять два шага, если вы не хотите:

getResultsAsynchronously().then(function (data) {
    doStuffWith(data);
    ...
});

.then также возвращает обещание, к которому вы можете прикрепить дополнительные обратные вызовы, позвонив по номеру .then или .catch.

В вашем коде

data = jq.run(filter, jsonPath).then(...).catch(...)

data - это просто еще одно обещание, но без какого-либо полезного возвращаемого значения (потому что ваши обратные вызовы then и catch не возвращают никакого значения).

Чтобы исправить вашу логику, она должна выглядеть так:

jq.run(filter, jsonPath).then((data) => {
    fs.appendFile('./jqTest.txt', data + "\r\n", (err) => {
        if (err) throw err;
        console.log("complete!")
    });
}).catch((err) => {
    console.error(err)
});

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

Тем не менее, async / await позволяет преобразовывать асинхронный код в синхронный код (или, по крайней мере, что-то, что выглядит синхронно). Однако этот трюк работает только «изнутри»: внешний интерфейс все еще асинхронный, вы можете просто написать более нормально выглядящий код внутри.

Например:

// await is only available inside async functions, so let's define one:
(async function () {

    // magic happens here:
    let data = await jq.run(filter, jsonPath);

    fs.appendFile('./jqTest.txt', data + "\r\n", (err) => {
        if (err) throw err;
        console.log("complete!")
    });

})();  // ... and invoke it immediately

Внутренне, JavaScript переписывает

x = await f();
doStuffWith(x);
...

в нечто, похожее на

return f().then((x) => {
    doStuffWith(x);
    ...
});

т.е. await позволяет вытащить содержимое функции обратного вызова в прямой код. Однако в конечном итоге вся функция async все еще возвращает обещание.

...