使用#groupBy

时间:2015-10-18 00:38:22

标签: javascript stream rxjs cartesian-product

我需要压缩分组的可观察量(形成相关群体的笛卡尔积,但这与问题无关)。

运行以下代码时,只有子可观察组实际上在#zip中发出值 - 为什么会这样?

https://jsbin.com/coqeqaxoci/edit?js,console

var parent = Rx.Observable.from([1,2,3]).publish();
var child = parent.map(x => x).publish();
var groupedParent = parent.groupBy(x => x);
var groupedChild = child.groupBy(x => x);

Rx.Observable.zip([groupedChild, groupedParent])
  .map(groups => {
    groups[0].subscribe(x => console.log('zipped child ' + x)); // -> emitting
    groups[1].subscribe(x => console.log('zipped parent ' + x)); // -> not emitting
  })
  .subscribe();

groupedChild.subscribe(group => {
  group.subscribe(value => console.log('child ' + value)); // -> emitting
});

groupedParent.subscribe(group => {
  group.subscribe(value => console.log('parent ' + value)); // -> emitting
});

child.connect();
parent.connect();

修改: 正如user3743222的回答中所解释的,groupBy发出的组是hot,并且在已经发出第一个值之后发生对父组(groups [1])的订阅。这是因为#zip等待groupedChild和groupedParent都发出,后者更快发出(意味着它的组在#zip函数运行之前发出值)。

1 个答案:

答案 0 :(得分:1)

我修改了你的代码如下:

var countChild = 0, countParent = 0;
function emits ( who ) {
  return function ( x ) {console.log(who + " emits : " + x);};
}
function checkCount ( who ) {
  return function ( ) {
    if (who === "parent") {
      countParent++;
    }
    else {
      countChild++;
    }
    console.log("Check : Parent groups = " + countParent + ", Child groups = " + countChild );
  };
}
function check ( who, where ) {
  return function ( x ) {
    console.log("Check : " + who + " : " + where + " :" + x);
  };
}
function completed ( who ) {
  return function () { console.log(who + " completed!");};
}
function zipped ( who ) {
  return function ( x ) { console.log('zipped ' + who + ' ' + x); };
}
function plus1 ( x ) {
  return x + 1;
}
function err () {
  console.log('error');
}

var parent = Rx.Observable.from([1, 2, 3, 4, 5, 6])
    .do(emits("parent"))
    .publish();
var child = parent
    .map(function ( x ) {return x;})
    .do(emits("child"))
//    .publish();

var groupedParent = parent
    .groupBy(function ( x ) { return x % 2;}, function ( x ) {return "P" + x;})
    .do(checkCount("parent"))
    .share();

var groupedChild = child
    .groupBy(function ( x ) { return x % 3;}, function (x) {return "C" + x;})
    .do(checkCount("child"))
    .share();

Rx.Observable.zip([groupedChild, groupedParent])
//    .do(function ( x ) { console.log("zip args : " + x);})
    .subscribe(function ( groups ) {
                 groups[0]
                     .do(function ( x ) { console.log("Child group observable emits : " + x);})
                     .subscribe(zipped('child'), err, completed('Child Group Observable'));
                 groups[1]
                     .do(function ( x ) { console.log("Parent group observable emits : " + x);})
                     .subscribe(zipped('parent'), err, completed('Parent Group Observable'));
               }, err, completed('zip'));

//child.connect();
parent.connect();

这是输出:

"parent emits : 1"
"child emits : 1"
"Check : Parent groups = 0, Child groups = 1"
"Check : Parent groups = 1, Child groups = 1"
"Parent group observable emits : P1"
"zipped parent P1"
"parent emits : 2"
"child emits : 2"
"Check : Parent groups = 1, Child groups = 2"
"Check : Parent groups = 2, Child groups = 2"
"Parent group observable emits : P2"
"zipped parent P2"
"parent emits : 3"
"child emits : 3"
"Check : Parent groups = 2, Child groups = 3"
"Parent group observable emits : P3"
"zipped parent P3"
"parent emits : 4"
"child emits : 4"
"Child group observable emits : C4"
"zipped child C4"
"Parent group observable emits : P4"
"zipped parent P4"
"parent emits : 5"
"child emits : 5"
"Child group observable emits : C5"
"zipped child C5"
"Parent group observable emits : P5"
"zipped parent P5"
"parent emits : 6"
"child emits : 6"
"Parent group observable emits : P6"
"zipped parent P6"
"Child Group Observable completed!"
"Child Group Observable completed!"
"Parent Group Observable completed!"
"Parent Group Observable completed!"
"zip completed!"

这里有两点要点:

  1. zip和group的行为与订阅时刻的关系

    • groupBy在父级和子级
    • 中按预期创建可观察对象

    使用这些值,您可以检查Child创建三个组的日志,Parent创建两个

    • Zip将等待您传递的每个源中的一个值作为参数。在您的情况下,这意味着您将同时订阅由可观察者分组的子项和父项。在日志中,只有在"Parent group observable emits : P1"上匹配数字后才能看到"Check : Parent groups = 1, Child groups = 1"

    • 然后,您订阅了两个分组的可观察对象,并记录从那里出来的任何内容。这里的问题是,通过observable分组的父有一个值可以传递,但是孩子' group-by' observable之前创建并且已经传递了它的值,所以当你在事后订阅时,你看不到那个值 - 但你会看到下一个。

    • 因此,[1-3]中的值将生成3个按可观察对象分组的新子项,您将看不到其中任何一个,因为您订阅的时间太晚。但是你会看到[4-6]中的值。您可以登录日志:"zipped child C4"等。

    • 您将看到父组中的所有值按可观察对象分组,因为您在创建后立即订阅它们。

  2. 连接并发布

    • 我对连接和发布没有完全清楚的理解,但是当您的孩子将父母作为来源时,您不需要延迟与它的连接。如果连接到父级,子级将自动开始发出其值。因此我修改了你的代码。

    • 那应该回答你当前的问题,但不是你最初的笛卡尔积的目标。也许你应该把它作为一个问题来制定,看看人们可以带来什么答案。