[英]RxJs - What is the proper pattern/way to create an Observable array of Observables?
[英]Deferred pattern with RxJS 5 observables
對於任意承諾實現,延遲模式(不要與反模式混淆)可能看起來像:
const deferred = new Deferred;
...
// scopes where `deferred` object reference was passed before promise settlement
deferred.promise.then((result) => { ... }, (error) => { ... });
...
deferred.resolve(...);
// doesn't affect promise state
deferred.reject();
...
// after promise settlement
deferred.promise.then((result) => { ... }, (error) => { ... });
deferred
對象包含可以通過引用傳遞給其他函數作用域的未定義的promise。 所有承諾鏈將在承諾解決執行,如果不要緊deferred.promise
與鏈接前和解then
或之后。 承諾狀態在結算后無法改變。
正如答案所示,最初的選擇是ReplaySubject
和AsyncSubject
。
對於給定的設置( 演示 )
var subject = new Rx.AsyncSubject;
var deferred = subject.first();
deferred.subscribe(
console.log.bind(console, 'Early result'),
console.log.bind(console, 'Early error')
);
setTimeout(() => {
deferred.subscribe(
console.log.bind(console, 'Late result'),
console.log.bind(console, 'Late error')
);
});
這導致了理想的行為:
subject.error('one');
subject.next('two');
早期錯誤一
遲到的錯誤一
這會導致不良行為:
subject.error('one');
subject.next('two');
subject.complete();
早期錯誤一
后期結果二
這會導致不良行為:
subject.next('two');
subject.complete();
subject.next('three');
早期結果二
后期結果三
ReplaySubject
的結果有所不同,但仍與預期結果不一致。 next
值和error
錯誤將單獨處理,並且complete
不會阻止觀察者接收新數據。 這可能適用於單個next
/ error
,問題是next
或error
可能會無意中多次調用。
使用first()
的原因是因為subscribe
是一次性訂閱,我想刪除它們以避免泄漏。
如何使用RxJS observable實現它?
您可能正在尋找Rx.ReplaySubject(1)
(或Rx.AsyncSubject()
具體取決於您的用例)。
有關主題的更詳細說明,請參閱不同RxJS主題的語義是什么? 。
基本上,主題可以通過引用傳遞,如延遲。 只要您持有該引用,就可以發出值(解析將是'next'
(Rxjs v5)或'onNext'
(Rxjs v4),然后是'complete'
或'onCompleted()'
)。
您可以擁有一個主題的任何數量的訂閱者,類似於then
的延遲。 如果你使用replaySubject(1)
,任何訂閱者都將收到最后一個發布的值,這應該回答你的it doesn't matter if deferred.promise was settled before chaining with then or after.
。 在Rxjs v4中, replaySubject
將在訂閱完成后向訂閱者發出其最后一個值。 我不確定Rxjs v5中的行為。
使用Rxjs v4執行以下代碼 :
var subject = new Rx.AsyncSubject();
var deferred = subject;
deferred.subscribe(
console.log.bind(console, 'First result'),
console.log.bind(console, 'First error')
);
setTimeout(() => {
deferred.subscribe(
console.log.bind(console, 'Second result'),
console.log.bind(console, 'Second error')
);
});
subject.onNext('one');
subject.onCompleted();
subject.onNext('two');
subject.onNext('three');
subject.onNext('four');
產生以下輸出:
First result one
Second result one
但是,使用Rxjs v5執行的相同代碼不會 :
First result one
Second result four
所以基本上這意味着主題的語義在Rxjs v5中發生了變化 ! 這真的是一個需要注意的突破性變化。 無論如何,你可以考慮回到Rxjs v4,或者在他的回答中使用artur grzesiak建議的轉變。 您還可以在github網站上提交問題。 我認為這種改變是故意的,但是在它出現的時候並非如此,提交這個問題可能有助於澄清這種情況。 在任何情況下,無論選擇何種行為都應該正確記錄。
正如@ user3743222編寫的AsyncSubject
可能在deferred
實現中使用,但問題是它必須是private
並且可以防止多個resolve
/ reject
。
以下是鏡像resolve-reject-promise
結構的可能實現:
const createDeferred = () => { const pending = new Rx.AsyncSubject(); // caches last value / error const end = (result) => { if (pending.isStopped) { console.warn('Deferred already resloved/rejected.'); // optionally throw return; } if (result.isValue) { pending.next(result.value); pending.complete(); } else { pending.error(result.error); } } return { resolve: (value) => end({isValue: true, value: value }), reject: (error) => end({isValue: false, error: error }), observable: pending.asObservable() // hide subject }; } // sync example let def = createDeferred(); let obs = def.observable; obs.subscribe(n => console.log('BEFORE-RESOLVE')); def.resolve(1); def.resolve(2); // warn - no action def.reject('ERROR') // warn - no action def.observable.subscribe(n => console.log('AFTER-RESOLVE')); // async example def = createDeferred(); def.observable.subscribe(() => console.log('ASYNC-BEFORE-RESOLVE')); setTimeout(() => { def.resolve(1); setTimeout(() => { def.observable.subscribe(() => console.log('ASYNC-AFTER-RESOLVE')); def.resolve(2); // warn def.reject('err'); // warn }, 1000) }, 1000); // async error example const def3 = createDeferred(); def3.observable.subscribe( (n) => console.log(n, 'ERROR-BEFORE-REJECTED (I will not be called)'), (err) => console.error('ERROR-BEFORE-REJECTED', err)); setTimeout(() => { def3.reject('ERR'); setTimeout(() => { def3.observable.subscribe( (n) => console.log(n, 'ERROR-AFTER-REJECTED (I will not be called)'), (err) => console.error('ERROR-AFTER-REJECTED', err)); def3.resolve(2); // warn def3.reject('err'); // warn }, 1000) }, 3000);
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.0.0-beta.9/Rx.umd.js"></script>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.