Заставить R.pipe работать с Promise?

Фон

У меня есть простой код, который составляет функции для печати Hello Mars!:

var greeting = () => "Hello ";
var dbQuery = str => Promise.resolve( `${str} Mars` );

var phrase = R.pipeP(
    greeting,
    dbQuery, 
    R.flip( R.concat )("!")
);

phrase();

проблема

я использую pipeP так как dbQuery возвращает обещание. У меня сложилось впечатление, что pipeP может сработать, если я преобразую весь код в обещания, но я действительно хочу этого избежать.

Моя идея заключалась в том, чтобы что-то вроде flatMapака chain в Рамде, но это тоже не работает.

Вопрос

Как я могу заставить этот код работать, не превращая все в Обещание?

MWE можно найти здесь

1 ответ

Решение

Когда вы работаете с Promise/Task/Future, вам не придется избегать обработки асинхронных данных и потока программ.

Как я могу заставить этот код работать, не превращая все в Обещание?

Под всем, вы имеете в виду эту часть?

// ...
phrase();

По той же причине троичный оператор ?: вынуждает вас включать обе ветви условных, асинхронных вызовов ожидают, что вы будете обрабатывать как успешную, так и ошибочную ветки Promise / Task / Future

// ...
phrase().then(onSuccess, onError);

Конечно, ничто не мешает тебе делать

const main = () =>
  phrase().then(console.log, console.error)

main()

И, как упоминает raina77ow, pipeP (и composeP) не рекомендуются. Мы можем исправить вашу программу, добавив простой then функция, которая легко вставляется в нормальный pipe (или же compose) последовательность функций

const greeting = () => "Hello ";
const dbQuery = str => Promise.resolve( `${str} Mars` );

const then = R.curry((f, p) => p.then(f))

const phrase = R.pipe(
  greeting,
  dbQuery,
  then(R.flip(R.concat)('!'))
);

phrase().then(console.log, console.error);
// Hello Mars!
// => { Promise 'Hello Mars!' }
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.js"></script>

Ниже я написал следующую вспомогательную функцию, которая должна решить вашу проблему. Он одинаково обрабатывает данные обещания и не обещания. Он также проверяет массивы с возвращаемыми обещаниями и, если да, обрабатывает их с помощьюPromise.all. Как и ожидалось, его окончательный результат будет обещанием.

function asyncPipe(...funcs){
  const reducer = async (val, func) => func(await (Array.isArray(val) ? Promise.all(val): val));
  return async val => await R.reduce(reducer, val, funcs)
}

Вот как использовать asyncPipe для вашей исходной проблемы с кодом:

function asyncPipe(...funcs){
  const reducer = async (val, func) => func(await (Array.isArray(val) ? Promise.all(val): val));
  return async val => await R.reduce(reducer, val, funcs)
}

var greeting = () => "Hello ";
var dbQuery = str => Promise.resolve( `${str} Mars` );

var phrase = asyncPipe(
    greeting,
    dbQuery, 
    R.flip( R.concat )("!")
);

phrase().then(console.log);

Ramda теперь включает функции then и else, поэтому лучше всего использовать их:

https://ramdajs.com/docs/

https://ramdajs.com/docs/

Другие вопросы по тегам