разумный способ передать / сохранить значение по длинной трубе

Предполагая, что у меня есть следующий канал rxjs:

start$.pip(
    map((id)=> {}), //I want to save the "id" value to be used in the end of the pipe
    map(...),
    switchMap(...),
    map(...),
    switchMap(...),
    map(...),
    switchMap(...),
    switchMap(...)//I need the original "id" value here
).subscribe()

Есть ли способ сохранить значение id во всем канале, чтобы его можно было использовать в конце канала?

Мотивация: это часто встречается в эффектах NGRX, когда я хочу использовать исходные данные полезной нагрузки действия источника запуска для генерации нового действия.


person amit    schedule 29.07.2018    source источник
comment
Я думаю, вам нужно передать идентификатор от одного оператора другому по всей цепочке. Вы можете попробовать что-то вроде этой карты (id = ›({id: id, data: data}))   -  person René Winkler    schedule 29.07.2018
comment
Сложно сказать без контекста, но я предлагаю начать с switchMap и создать вложенный канал внутри.   -  person a better oliver    schedule 29.07.2018


Ответы (3)


Я думаю, что правильный способ - сделать еще одно закрытие

const processId = (id) => observableOf(id)
  .pipe(
    map(() => { ... }),
    map(...),
    switchMap(...),
    map(...),
    switchMap(...),
    map(...),
    switchMap(...),
    switchMap(...) // Use id here
  );

const getPipe = () => start$
  .pipe(switchMap(processId));

Сохранение локальной переменной в качестве побочного эффекта в getPipe - это нормально, но это может сломаться, если start$ Observable испускает больше значений.

person m1ch4ls    schedule 29.07.2018

Способ, предложенный @ René Winkler, - правильный путь для коротких трубок.

Если канал длинный, это может быть утомительно и каким-то образом может сделать код менее читаемым.

Один из альтернативных подходов может заключаться в создании функции (или метода), в которой вы определяете id как локальную переменную, которую вы устанавливаете в первой map, чтобы вы могли использовать ее по своему усмотрению во всей цепочке операторов, что-то вроде

getLongPipe(id) {
  let _id;
  return start$.pipe(
    map((id)=> {_id = id; ....}), //I want to save the "id" value to be used in the end of the pipe
    map(...),
    switchMap(...),
    map(...),
    switchMap(...),
    map(...),
    switchMap(...),
    switchMap(...)//Here you can use _id
  )
}

getLongPipe(id).subscribe()
person Picci    schedule 29.07.2018
comment
Ты прав. Я писал о входной переменной, в то время как имел в виду локальную переменную. См. Обновленный ответ. - person Picci; 29.07.2018

Замыкание кажется правильным, я хотел бы добавить подробности, я свелся к базовому случаю:

Допустим, вы хотите добраться до конца потока и, основываясь на том, что произошло раньше, сделайте то или это. Итак, вы используете шаблон закрытия, начинаете с флага false, а затем в конвейере устанавливаете его в true. В конце трубы сделайте то или иное в зависимости от флага. Прекрасно работает.

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

Основная форма / исправление:

stream$ = ( ( my_flag = false ) => {
    return ( otherStream$
        .variousOperators ( ... )
        .do ( x => { 
           my_flag = some_condition_of_x ? true : false
        } )
        .map ( x => my_flag ? a : b )
        .do ( x => {
          my_flag = false; // reset
        } )
        .map ( x => x )
    );
  } ) ();

Был довольно сложный случай, связанный с некоторыми эффектами NGRX, который был значительно (значительно) упрощен этим.

person Tim Consolazio    schedule 08.11.2018