Заставить 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
в Рамде, но это тоже не работает.
Вопрос
Как я могу заставить этот код работать, не превращая все в Обещание?
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, поэтому лучше всего использовать их: