使用flatMap或flatMapConcat以正确的顺序顺序合并流

时间:2014-12-27 15:18:09

标签: javascript node.js bacon.js

我有两个流:

  • getPost是一个fromPromise流,用于投放单个帖子。示例:author done
  • getPostsStream流式传输给定作者的帖子列表。示例:a1 done, a2 done

我有3位作者,它也是一个流,示例:Bacon.fromArray(["a", "b", "c"])

我希望通过组合这些流来获取作者的帖子:

我有两个条件:

  • 顺序:每个作者发一个帖子,然后是每个作者的下一个帖子。 sample: a1--b1--c1--a2--b2--c2
  • 并发:getPost流无法并行运行(导致许多http请求),sample: a1--b1--c1 should happen sequentially, it shouldn't burst.

以下是代码:

 var getPost = function(author) {
   return Bacon.fromPromise(new RSVP.Promise(function(resolve) {
     setTimeout(function() { resolve(author + " done"); }, 1000);
   }));
 };

 var getPostsStream = function(author) {
   return Bacon.fromArray([1, 2, 3, 4]).flatMapConcat(function(v) {
     return getPost(author + v);
   });
 };

 var combinedFlatMap = Bacon.fromArray(["a", "b", "c"]).flatMap(function(v) {
   return getPostsStream(v);
 });

 var combinedFlatMapConcat = Bacon.fromArray(["a", "b", "c"]).flatMapConcat(function(v) {
   return getPostsStream(v);
 });

 //combinedFlatMap.log();
 combinedFlatMapConcat.log();

我在作者流上做flatMap并返回该作者的帖子流。这导致:

a1 done
b1 done
c1 done
a2 done
b2 done
c2 done

但是a1--b1--c1突然出现,所以没有并发限制为1。

我做flatMapConcat

a1 done
a2 done
a3 done
a4 done
b1 done
b2 done
b3 done
b4 done

这可以按照我想要的顺序工作,但这次它不按顺序。

修改

我玩过溪流,知道各种组合器是如何工作的。我最后的工作是两个流getPostsStream(author)author流。我无法将这些与正确的顺序结合起来。哪个是a1 b1 a2 b2,所以one post from each getPostsStream(author) and back。你的例子是错的,尝试使用我的流:

  • 作者流:Bacon.fromArray(["a", "b", "c"])
  • 来自上面例子的postsStream:getPostsStream(author)

我需要的是,使用这两个流产生输出:

a1 done `wait 1 sec`
b1 done `wait 1 sec`
c1 done `wait 1 sec`
a2 done `wait 1 sec`
b2 done `wait 1 sec`
c2 done `wait 1 sec`

请注意,字母a b c代表作者,而数字1 2 3代表帖子。

如何在并发限制为1的情况下实现正确的顺序?

1 个答案:

答案 0 :(得分:0)

您是否尝试过observable.flatMapFirst(f) flatMap,但仅在以前生成的流已结束时生成新流。

修改

开始简单。如果我们想要订单a1-a2-b1-b2,那么我们首先按正确的顺序制作一系列事件。之后,我们flatMapWithConcurrencyLimit(1, getPost)flatMapConcat(getPost)getPost(或其他Promise - 返回功能)。

Bacon.fromArray(["a1", "a2", "b1", "b2"]).flatMapConcat(function (x) { 
  return Bacon.fromPromise(new Promise(function (resolve) {
    console.log("start  " + x + " " + new Date().getTime());
    setTimeout(function () {
      resolve(x + " " + new Date().getTime());
    }, 2000);
  }));
}).log("output");

结果:

start  a1 1419796654587
output a1 1419796656589
start  a2 1419796656589
output a2 1419796658591
start  b1 1419796658592
output b1 1419796660593
tart  b2 1419796660594
output b2 1419796662595
output <end>

另一个编辑

如果您从作者流(a-b-c-d)开始,使用正确的排序(a1-b1-c1-d1-a2-b2...)获取帖子流非常复杂。

  • 如果作者流是异步无限a..b....c..d..),则无法知道何时可以获取第一作者的第二篇文章。
  • 如果作者流是异步有限,那么你可能会比你不想等到作者流结束(这需要很长时间)< / LI>
  • 如果流是同步有限fromArray),那么尽可能长时间地停留在数组世界中要简单得多。在这种情况下,你可以使用下划线或lodash以正确的顺序排列提取物,然后进入异步的培根世界。

var authors = ['a', 'b', 'c', 'd'];
var postIdsByAuthor = _.map(authors, function (a) {
  return _.map([1, 2, 3, 4], function (i) {
    return a + i;
  });
});
var postIds = _.flatten(_.zip.apply(null, postIdsByAuthor));
// ["a1", "b1", "c1", "d1", "a2", "b2", "c2", "d2", "a3", "b3", "c3", "d3", "a4", "b4", "c4", "d4"]

transpose trick

异步案例可以解决,但不能使用单个内置组合器。然而,你的问题并不清楚。然而,合理的限制将是 - 以循环方式获取作者的帖子 - 让getPost“工人”始终忙碌

所以一种情况是(水平轴上的时间)

authors: a....b........c....................
getPost: a1.a2.b1.a3.b2.c1.a4.b3.c2.b4.c3.c4

P.S。如果您或某人拒绝回答,请评论原因。