为什么 flatMap 和 fromEvent 仅在第一次订阅期间返回时才起作用?
Why does flatMap and fromEvent work only when returning it during first subscription as per example?
如下所示,当我们 return div 然后单独 return 一个新的 click observable flatMap 到 click$
时,为什么示例 1 会失败?
示例 2 工作正常。下面的JSBin试试看
谁能解释为什么会这样?据我了解,flatMap 扩展了 Observable。
http://jsbin.com/sowodi/3/edit?js,console,output
// Example 1
() => {
let stream = Rx.Observable.fromArray([1, 2, 3]);
let div$ = stream.map(i => {
let div = document.createElement('div');
div.innerHTML = `NOT WORKING DIV ${i}`;
return div;
})
div$.subscribe(div => {
document.querySelector('body').appendChild(div);
})
let click$ = div$.flatMap(
div => Rx.Observable.fromEvent(div, 'click')
);
click$.subscribe(click => console.log('click'));
}();
// Example 2
() => {
let stream = Rx.Observable.fromArray([4, 5, 6]);
let click$ = stream.flatMap(i => {
let div = document.createElement('div');
div.innerHTML = `DIV ${i}`;
document.querySelector('body').appendChild(div);
return Rx.Observable.fromEvent(div, 'click');
})
click$.subscribe(click => console.log('click'));
}();
<!DOCTYPE html>
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/4.0.6/rx.all.js"></script>
<meta charset="utf-8">
<title>JS Bin</title>
</head>
<body>
<div id="app">
THE APP ID
</div>
</body>
</html>
这是因为在您的第一个示例中,您创建了两组 div。您已经完成了相当于此的操作:
Rx.Observable.fromArray([1, 2, 3])
.map(i => {
let div = document.createElement('div');
div.innerHTML = `NOT WORKING DIV ${i}`;
return div;
}).subscribe(div => {
document.querySelector('body').appendChild(div);
})
Rx.Observable.fromArray([1, 2, 3])
.map(i => {
let div = document.createElement('div');
div.innerHTML = `NOT WORKING DIV ${i}`;
return div;
}).flatMap(
div => Rx.Observable.fromEvent(div, 'click')
).subscribe(click => console.log('click'));
为什么,这是因为 fromArray
创建了一个 cold Observable
意味着每个订阅都会创建一个全新的独立流,不会影响您创建的任何其他流。
有两种方法可以修复它,1) 您已经发现的是只创建一个流来容纳您的所有逻辑,或者 2) 或者您可以将 div$ 的结果转换为热 Observable
这样所有订阅实际上都将共享相同的流。这将带来一系列问题,即如果您不小心,您现在可能会错过消息,但要重构您的第一个案例,它最终看起来像:
let stream = Rx.Observable.fromArray([1, 2, 3]);
let div$ = stream.map(i => {
let div = document.createElement('div');
div.innerHTML = `NOT WORKING DIV ${i}`;
return div;
})
//Make div$ into a connectable Observable so the subscriptions will
//share the underlying Observable
.publish()
div$.subscribe(div => {
document.querySelector('body').appendChild(div);
})
let click$ = div$.flatMap(
div => Rx.Observable.fromEvent(div, 'click')
);
click$.subscribe(click => console.log('click'));
//Nothing happens until you call connect which subscribes to the underlying
//Observable
div$.connect();
如下所示,当我们 return div 然后单独 return 一个新的 click observable flatMap 到 click$
时,为什么示例 1 会失败?
示例 2 工作正常。下面的JSBin试试看
谁能解释为什么会这样?据我了解,flatMap 扩展了 Observable。 http://jsbin.com/sowodi/3/edit?js,console,output
// Example 1
() => {
let stream = Rx.Observable.fromArray([1, 2, 3]);
let div$ = stream.map(i => {
let div = document.createElement('div');
div.innerHTML = `NOT WORKING DIV ${i}`;
return div;
})
div$.subscribe(div => {
document.querySelector('body').appendChild(div);
})
let click$ = div$.flatMap(
div => Rx.Observable.fromEvent(div, 'click')
);
click$.subscribe(click => console.log('click'));
}();
// Example 2
() => {
let stream = Rx.Observable.fromArray([4, 5, 6]);
let click$ = stream.flatMap(i => {
let div = document.createElement('div');
div.innerHTML = `DIV ${i}`;
document.querySelector('body').appendChild(div);
return Rx.Observable.fromEvent(div, 'click');
})
click$.subscribe(click => console.log('click'));
}();
<!DOCTYPE html>
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/4.0.6/rx.all.js"></script>
<meta charset="utf-8">
<title>JS Bin</title>
</head>
<body>
<div id="app">
THE APP ID
</div>
</body>
</html>
这是因为在您的第一个示例中,您创建了两组 div。您已经完成了相当于此的操作:
Rx.Observable.fromArray([1, 2, 3])
.map(i => {
let div = document.createElement('div');
div.innerHTML = `NOT WORKING DIV ${i}`;
return div;
}).subscribe(div => {
document.querySelector('body').appendChild(div);
})
Rx.Observable.fromArray([1, 2, 3])
.map(i => {
let div = document.createElement('div');
div.innerHTML = `NOT WORKING DIV ${i}`;
return div;
}).flatMap(
div => Rx.Observable.fromEvent(div, 'click')
).subscribe(click => console.log('click'));
为什么,这是因为 fromArray
创建了一个 cold Observable
意味着每个订阅都会创建一个全新的独立流,不会影响您创建的任何其他流。
有两种方法可以修复它,1) 您已经发现的是只创建一个流来容纳您的所有逻辑,或者 2) 或者您可以将 div$ 的结果转换为热 Observable
这样所有订阅实际上都将共享相同的流。这将带来一系列问题,即如果您不小心,您现在可能会错过消息,但要重构您的第一个案例,它最终看起来像:
let stream = Rx.Observable.fromArray([1, 2, 3]);
let div$ = stream.map(i => {
let div = document.createElement('div');
div.innerHTML = `NOT WORKING DIV ${i}`;
return div;
})
//Make div$ into a connectable Observable so the subscriptions will
//share the underlying Observable
.publish()
div$.subscribe(div => {
document.querySelector('body').appendChild(div);
})
let click$ = div$.flatMap(
div => Rx.Observable.fromEvent(div, 'click')
);
click$.subscribe(click => console.log('click'));
//Nothing happens until you call connect which subscribes to the underlying
//Observable
div$.connect();