RXJS контролирует наблюдаемый вызов

Я использую RxJs версии 5 в моем проекте Angular 2. Я хочу создать некоторые наблюдаемые, но я не хочу, чтобы наблюдаемые вызывались немедленно.

В версия 4 вы можете управлять вызовом с помощью (например) Controlled или Допустимые буферы. Но эта функциональность отсутствует (пока), доступной в версии 5.

Как я могу получить такую ​​функциональность в RxJs 5?

Моя конечная цель - поставить в очередь созданные наблюдаемые и вызвать их по одному. Следующий вызов запускается только при успешной обработке предыдущего. Когда кто-то терпит неудачу, очередь опустеет.

ИЗМЕНИТЬ

С комментарием @Niklas Fasching я мог бы создать рабочее решение с Publish.

JS Bin

// Queue to queue operations
const queue = [];

// Just a function to create Observers
function createObserver(id): Observer {
    return {
        next: function (x) {
            console.log('Next: ' + id + x);
        },
        error: function (err) {
            console.log('Error: ' + err);
        },
        complete: function () {
            console.log('Completed');
        }
    };
};

// Creates an async operation and add it to the queue
function createOperation(name: string): Observable {

  console.log('add ' + name);
  // Create an async operation
  var observable = Rx.Observable.create(observer => {
    // Some async operation
    setTimeout(() => 
               observer.next(' Done'), 
               500);
  });
  // Hold the operation
  var published = observable.publish();
  // Add Global subscribe
  published.subscribe(createObserver('Global'));
  // Add it to the queue
  queue.push(published);
  // Return the published so the caller could add a subscribe
  return published;
};

// Create 4 operations on hold
createOperation('SourceA').subscribe(createObserver('SourceA'));
createOperation('SourceB').subscribe(createObserver('SourceB'));
createOperation('SourceC').subscribe(createObserver('SourceC'));
createOperation('SourceD').subscribe(createObserver('SourceD'));

// Dequeue and run the first
queue.shift().connect();

Ответ 1

Вы можете отделить начало наблюдаемого от подписки на него публикацию наблюдаемого. Опубликованный наблюдаемый будет запущен только после вызова connect на нем.

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

var published = Observable.of(42).publish();
// subscription does not start the observable sequence
published.subscribe(value => console.log('received: ', value));
// connect starts the sequence; subscribers will now receive values
published.connect();

Ответ 2

С Rx4 controlled Наблюдаемый по-прежнему вызывается, когда вы подписываетесь

Оператор controlled в RxJS 4 действительно контролировал поток Observable после оператора. До этого момента все насосы и буферы на этом операторе. Рассмотрим это:

(RxJS 4) http://jsbin.com/yaqabe/1/edit?html,js,console

const source = Rx.Observable.range(0, 5).do(x => console.log('do' + x)).controlled();

source.subscribe(x => console.log(x));

setTimeout(() => {
  console.log('requesting');
  source.request(2);
}, 1000);

Вы заметите, что все пять значений из Observable.range(0, 5) испускаются с помощью do немедленно... затем пауза в одну секунду (1000 мс), прежде чем вы получите два значения.

Итак, это действительно иллюзия контроля противодавления. В конце концов, в этом операторе есть неограниченный буфер. Массив, который собирает все, что Наблюдаемый "выше" отправляет и ждет вас, чтобы удалить его, вызвав request(n).


RxJS 5.0.0-beta.2 репликация controlled

Во время этого ответа оператор controlled не существует в RxJS 5. Это по нескольким причинам: 1. Нет запросов для него и 2. Его имя явно запутывает (отсюда этот вопрос на StackOverflow )

Как реплицировать поведение в RxJS 5 (пока): http://jsbin.com/metuyab/1/edit?html,js,console

// A subject we'll use to zip with the source
const controller = new Rx.Subject();

// A request function to next values into the subject
function request(count) {
  for (let i = 0; i < count; i++) {
    controller.next(count);
  }
}

// We'll zip our source with the subject, we don't care about what
// comes out of the Subject, so we'll drop that.
const source = Rx.Observable.range(0, 5).zip(controller, (x, _) => x);

// Same effect as above Rx 4 example
source.subscribe(x => console.log(x));

// Same effect as above Rx 4 example
request(3);

Управление обратным давлением

Для "реального контроля обратного давления" прямо сейчас одно решение является итератором обещания. IoP не без проблем, хотя, с одной стороны, есть распределение объектов на каждом шагу. Каждое значение имеет связанное с ним обещание. С другой стороны, отмены не существует, потому что это promises.

Лучший подход на основе Rx состоит в том, чтобы иметь тему, которая "подает" верхнюю часть вашей наблюдаемой цепи, и вы составляете в остальном.

Что-то вроде этого: http://jsbin.com/qeqaxo/2/edit?js,console

// start with 5 values
const controller = new Rx.BehaviorSubject(5);

// some observable source, in this case, an interval.
const source = Rx.Observable.interval(100)

const controlled = controller.flatMap(
      // map your count into a set of values
      (count) => source.take(count), 
      // additional mapping for metadata about when the block is done
      (count, value, _, index) => {
        return { value: value, done: count - index === 1 }; 
      })
      // when the block is done, request 5 more.
      .do(({done}) => done && controller.next(5))
      // we only care about the value for output
      .map(({value}) => value);


// start our subscription
controlled.subscribe(x => {
  console.log(x)
});

... у нас есть планы плавного наблюдаемого типа с реальным контролем противодавления в ближайшем будущем. Это будет более захватывающим и намного лучше для такого рода сценариев.