简体   繁体   English

Promise.all 在带有 FP 的承诺的对象数组上

[英]Promise.all on array of objects with promises with FP

So, I'm using NodeJS and Ramda and I have an Array of objects like:所以,我正在使用 NodeJS 和 Ramda,并且我有一个对象数组,例如:

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

Then I want do use x in a request which returns a promise, resulting in this (using over and lensProp from Ramda):然后我想在返回承诺的请求中使用x ,结果是(使用来自lensProp overlensProp ):

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

Now I want to turn that last array into this:现在我想把最后一个数组变成这个:

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

How can I achieve that in a functional way (as in functional programming, not as in something that just works =])?我怎样才能以函数式的方式实现这一点(就像在函数式编程中一样,而不是像在正常工作的东西中那样 =])?

The best I could think of was to get all the promises from x , use Promise.all and use then to zip the result back with the y s.我能想到的最好的方法是从x获取所有承诺,使用Promise.all并使用then将结果zipy s。 But I'm not accepting that as a solution.但我不接受这是一个解决方案。

One option is to introduce a new helper function which behaves similar to R.traverse that is specialised to Promises and will work over a specific property of an object.一种选择是引入一个新的辅助函数,它的行为类似于R.traverse ,专门用于 Promises 并且将处理对象的特定属性。 Let's call this traversePropP :我们称之为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)))

This effectively lets you produce a Promise from the specified property of an object, replacing the property with the eventual value resolved by the created Promise.这有效地让您从对象的指定属性生成一个 Promise,用创建的 Promise 解析的最终值替换该属性。

You can then use this new function to map over all the objects in your array, then pass the resulting array of Promises to Promise.all .然后,您可以使用这个新函数来映射数组中的所有对象,然后将生成的Promise.all数组传递给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>

Here is a clean way to do what you want.这是一个干净的方法来做你想做的事。

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)

final output is a promise of an array of objects with x properties overwritten with the result of the requests最终输出是一个对象数组的承诺,其中x属性被请求的结果覆盖

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM