让 R.pipe 使用 Promise?

Make R.pipe work with a 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 returns 一个 Promise。我的印象是,如果我将整个代码转换为 promise,pipeP 就可以工作,但是 我真的很想避免这种情况

我的想法是 flatMap,在 Ramda 中又名 chain,但这也行不通。

问题

如何在不将所有内容都转换为 Promise 的情况下使此代码工作?

A MWE can be found here

一旦处理 Promise/Task/Future,就不可避免地要处理异步数据和程序流

How can I make this code work without converting everything into a Promise?

一切,你指的是这一部分吗?

// ...
phrase();

出于同样的原因,三元运算符 ?: 强制您包括 both 个条件分支,异步调用希望您处理两个成功的 Promise/Task/Future

的错误分支
// ...
phrase().then(onSuccess, onError);

当然没有什么能阻止你做

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

main()

raina77ow mentions, pipeP (and composeP) are not recommended一样。我们可以通过添加一个简单的 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>

Ramda 现在包含 then 和 otherwise 函数,所以最好使用这些函数:

https://ramdajs.com/docs/#andThen

https://ramdajs.com/docs/#otherwise

我在下面编写了以下辅助函数,应该可以解决您的问题。它平等地处理承诺和非承诺数据。它还检查返回承诺的数组,如果是,则使用 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);