Javascript RxJS Promise 组合(传递数据)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/34701304/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 16:45:29  来源:igfitidea点击:

RxJS Promise Composition (passing data)

javascriptfunctional-programmingrxjsfrpramda.js

提问by low_ghost

I'm brand new to Rx and am finding it difficult to find documentation on composing promises such that data from the first promise is passed into the second and so on. Here's three very basic promises, the calculations on the data aren't important, just that something async has to be done using data from the previous promise.

我是 Rx 的新手,我发现很难找到有关撰写承诺的文档,以便将第一个承诺中的数据传递到第二个承诺中,依此类推。这是三个非常基本的承诺,对数据的计算并不重要,只是必须使用前一个承诺中的数据进行异步操作。

 const p1 = () => Promise.resolve(1);
 const p2 = x => { const val = x + 1; return Promise.resolve(val); };
 const p3 = x => {
      const isEven = x => x % 2 === 0;
      return Promise.resolve(isEven(x));
 };

The traditional way to achieve the composition I'm talking about:

实现我所说的组合的传统方法:

 pl().then(p2).then(p3).then(console.log);

My favorite implementation is Ramda's composeP and pipeP:

我最喜欢的实现是 Ramda 的 composeP 和 pipeP:

R.pipeP(p1, p2, p3, console.log)()

It seems likely Rx might be able to handle this kind of situation pretty fluently. However, the closest I've found so far is from the RxJS to async (library) comparison here https://github.com/Reactive-Extensions/RxJS/blob/master/doc/mapping/async/comparing.md:

看起来 Rx 可能能够非常流畅地处理这种情况。但是,到目前为止我发现的最接近的是从 RxJS 到异步(库)比较这里https://github.com/Reactive-Extensions/RxJS/blob/master/doc/mapping/async/comparing.md

 var Rx = require('rx'),
     fs = require('fs'),
     path = require('path');
 var file = path.join(__dirname, 'file.txt'),
     dest = path.join(__dirname, 'file1.txt'),
     exists = Rx.Observable.fromCallback(fs.exists),
     rename = Rx.Observable.fromNodeCallback(fs.rename),
     stat = Rx.Observable.fromNodeCallback(fs.stat);
 exists(file)
    .concatMap(function (flag) {
     return flag ?
         rename(file, dest) :
         Rx.Observable.throw(new Error('File does not exist.'));
    })
    .concatMap(function () {
        return stat(dest);
    })
   .forEach(
      function (fsStat) {
          console.log(JSON.stringify(fsStat));
      },
      function (err) {
          console.log(err);
      }
    );

concatMap seems promising, but the above code looks pretty horrific. I was also having trouble with my example because Rx.Observable.fromPromise(p1) won't work as it expects a promise itself, not a function, and Rx.Observable.defer(p1) doesn't seem to pass parameters like the example.

concatMap 看起来很有希望,但上面的代码看起来非常可怕。我的例子也有问题,因为 Rx.Observable.fromPromise(p1) 不会工作,因为它期望一个承诺本身,而不是一个函数,而且 Rx.Observable.defer(p1) 似乎没有传递像例子。

Thanks!

谢谢!

Similar question but without data passing: Chaining promises with RxJS

类似的问题,但没有数据传递: Chaining promises with RxJS

回答by user3743222

I did not read all of it, but if you want to achieve the same as pl().then(p2).then(p3).then(console.log);, with pbeing function returning promises, you could do something like (example here)

我没有阅读所有内容,但是如果您想实现与 相同的功能pl().then(p2).then(p3).then(console.log);,并p通过函数返回承诺,您可以执行类似的操作(此处的示例)

Rx.Observable.fromPromise(p1())
             .flatMap(function(p1_result){return p2(p1_result);})
             .flatMap(function(p2_result){return p3(p2_result);})

Or the more symmetric :

或者更对称:

 var chainedPromises$ = 
     Rx.Observable.just()
             .flatMap(p1)
             .flatMap(p2)
             .flatMap(p3);

Now if you want to execute sequentially callback wrapped through fromCallbackor fromNodeCallback, you could do something like :

现在,如果您想通过fromCallbackor执行顺序回调fromNodeCallback,您可以执行以下操作:

function rename (flag){
  return flag
          ? rename(file,dest).flatMap(return Rx.Observable.just(dest))
          : Rx.Observable.throw(new Error('File does not exist.'));
}

Rx.Observable.just(file)
             .flatMap(exists)
             .flatMap(rename)
             .flatMap(stat)

The latter code is untested, so keep me updated if that works. Last comment, this should work if at each point you only have one value produced (like a promise). If you would have several files instead of one, with flatMapyou might get ordering issues (if order matters to you), so in that case, you could use concatMapas a replacement.

后一个代码未经测试,所以如果有效,请让我更新。最后一条评论,如果在每个点您只产生一个值(如承诺),这应该有效。如果您有多个文件而不是一个文件,flatMap那么您可能会遇到排序问题(如果订单对您很重要),那么在这种情况下,您可以将其concatMap用作替代品。