Promise.all关于带有FP承诺的对象数组

时间:2018-07-28 05:33:36

标签: javascript node.js functional-programming ramda.js

所以,我正在使用NodeJS和Ramda,并且我有一个对象数组:

[
    {
        x: 'abc',
        y: []
    },
    {
        x: '123',
        y: [1, 2, 3]
    }
]

然后我想在返回诺言的请求中使用x,从而导致此结果(使用Ramda的overlensProp):

[
    {
        x: Promise<String>,
        y: []
    },
    {
        x: Promise<String>,
        y: [1, 2, 3]
    }
]

现在我想把最后一个数组变成这个:

Promise<[
    {
        x: String,
        y: []
    },
    {
        x: String,
        y: [1, 2, 3]
    }
]>

我该如何以一种功能的方式来实现这一目标(就像在函数式编程中那样,而不是在某些可行的方法中==)?

我能想到的最好的办法是从x获得所有承诺,使用Promise.all并使用thenzip的结果与{{1} } s。但是我不接受这作为解决方案。

2 个答案:

答案 0 :(得分:1)

一个选择是引入一个行为类似于R.traverse的新帮助程序函数,该函数专用于Promises,并且可以处理对象的特定属性。我们称之为traversePropP

// traversePropP :: (a -> Promise b) -> String -> {a|...} -> Promise {b|...}
const traversePropP = R.curry((toPromiseFn, prop, obj) =>
  toPromiseFn(obj[prop]).then(v => R.assoc(prop, v, obj)))

这有效地使您可以从对象的指定属性中生成一个Promise,用创建的Promise解析的最终值替换该属性。

然后,您可以使用此新功能来映射数组中的所有对象,然后将所得的Promises数组传递给Promise.all

const traversePropP = R.curry((toPromiseFn, prop, obj) =>
  toPromiseFn(obj[prop]).then(v => R.assoc(prop, v, obj)))

// example Promise-producing function that delays a value
const delayP = n => x =>
  new Promise((res, rej) => setTimeout(() => res(x), n))

const fn = R.pipe(
  R.map(traversePropP(delayP(500), 'x')),
  x => Promise.all(x)
)

const data = [
    {
        x: 'abc',
        y: []
    },
    {
        x: '123',
        y: [1, 2, 3]
    }
]

console.log('begin')
fn(data).then(x => console.log('result:', x))
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>

答案 1 :(得分:0)

这是做自己想要的事的一种干净方法。

import { pipe, assign, map, get } from 'rubico'

const makeRequest = async x => {/* ... */}

const data = [
  { x: 'abc', y: [] },
  { x: '123', y: [1, 2, 3] },
]

map(assign({
  x: pipe([get('x'), makeRequest]),
}))(data)

最终输出是对对象数组的承诺,这些对象的x属性被请求的结果覆盖