2016-03-11 2 views
9

Я хотел использовать rxjs в первый раз, но я немного застрял, потому что он не ведет себя точно так, как я хочу: в моем сценарии я хочу создать наблюдаемое из обещания , Но я хочу, чтобы обещание вызывалось только один раз (не на каждой подписке), и я хочу, чтобы он не вызывался во время создания (отложите вызов до первой подписки).rxjs, используя обещание только один раз на подписке

Сначала я попытался это:

var source = Rx.Observable.fromPromise(_this.getMyPromise()) 

, который вызывает вызов функции getMyPromise прямо на момент создания. Это не удовлетворяет, потому что в то время я не знаю, будет ли источник действительно использоваться.

Тогда я попробовал:

var source = Rx.Observable.defer(function() { return _this.getMyPromise() }) 

, который вызывает вызов функции getMyPromise каждый раз, когда создается новая подписка делается на источник. Это делает слишком много ненужных вызовов на веб-сервер. Функция Rx.Observable.create, похоже, имеет такую ​​же проблему.

Итак, что осталось или чего мне не хватает?

+0

Таким образом, вы хотите, чтобы он был вызван один раз, но что вы хотите, если он вызывается после того, как он уже завершен? – John

ответ

5

.shareReplay() это делает, например:

var source = Rx.Observable.defer(function() { return _this.getMyPromise() }).shareReplay(); 

Если вы используете rxjs5, вы хотите прочитать: Pattern for shareReplay(1) in RxJS5

В ответ на ваш комментарий ниже, я могу думать о довольно простой расширение к вышеуказанной логике, которая будет делать то, что вы хотите, но имеет оговорку. Скажем, событие, которые вы хотите использовать, чтобы вызвать «Refresh» представлены в потоке, S $, то вы могли бы сделать что-то вроде:

var source = Rx.Observable.of({}).concat(s$) 
    .flatMapLatest(function() { 
     return Rx.Observable.defer(function() { 
      return _this.getMyPromise() 
     }) 
    }) 
    .shareReplay(1) 

То, что мы имеем здесь поток, начиная с фиктивным объектом сверните вещи, а затем поток, состоящий из ваших событий обновления. Каждый из них проецируется в новый наблюдаемый, созданный из нового вызова вашего метода getMyPromise, и все это сглаживается в один поток. Наконец, мы сохраняем логику shareReplay, поэтому мы только на самом деле делаем звонки, когда хотим.

Предостережение заключается в том, что это будет работать только в том случае, если у источника всегда есть хотя бы один абонент (первая подписка после того, как все остальные будут удалены, снова запустит обещание и получит как ранее кэшированное значение, так и результат от обещания, которое оно вызвало для запуска).

+0

Это замечательно. Благодаря! Есть ли способ объединить ваше решение с механизмом перезагрузки при обратном вызове? -> Увольняется событие, на котором я мог бы выполнить вызов по методу rxjs-callback. Когда этот метод вызывается, он выполняет новый вызов на _this.getMyPromise(), и каждый абонент получает информацию о новых данных? Я знаю, что это гораздо больше, чем я спросил, но это просто следующее, что приходит мне на ум ... – Domenic

+0

TBH, я немного озадачен тем, что fromPromise не принимает обратный вызов, как все остальное. – DarkNeuron

0

Вот ответ, который не требует, по меньшей мере одного абонента у источника в любое время с помощью простого помощника:

var _p = null; 
var once = function() { return _p || (_p = _this.getMyPromise()); 

var source = Rx.Observable.defer(once); 

Или, если вы используете lodash, вы можете _.memoize свой getMyPromise и получить это автоматически.

+0

Оговорка в моем ответе применима только к второму требованию. Как можно адаптировать этот подход для решения этой проблемы? Установка _p обратно на нуль приведет к тому, что новые подписчики получат новое обещание, но как бы вы договорились о выходе нового обещания существующим подписчикам? –

Смежные вопросы