Оператор rxjs, который добавляет ведение журнала до и после обратного вызова

Я пытаюсь повернуть это:

/* ...inside a pipe */
tap(() => logData('my process')),
tap(() => someCallback()),
tap(() => logDataEnd('my process'),
/* pipe continues */

В новый оператор, который принимает обратный вызов () => someCallback() и добавляет побочные эффекты журналирования до и после него. Мои функции ведения журнала используют performance.now(), и они работают должным образом *, когда я просто использую явную tap версию, но ни один из моих операторов не делает то же самое.

Ожидаемые результаты

Труба с использованием моего оператора:

of(null).pipe(
  withLogging(() => callbackA()),
  withLogging(() => callbackB()),
  /* etc. */
)

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

Action A start
Action A end
Action B start
Action B end
...

Однако я получаю это:

Action A start
Action B start
/* ... rest of the pipe */
Action A end
Action B end

Посмотрев на временные метки, я вижу, что журналы end имеют правильные метки времени, но begin - слишком рано.

Я пробовал использовать defer по-разному, но результат не изменился.

Что я пробовал

withLogging<T, R>(project: (value :T) => R): OperatorFunction<T, R> {
  return (source: Observable<T>) =>
  defer(() => of(startLogging())).pipe(
    flatMap(() => source),
    tap(() => stopLogging())
  );
}

Я пробовал обернуть весь канал defer или просто начать процесс регистрации, или сделать of(null).pipe, а затем объединить все эффекты. Я даже пробовал вообще не использовать defer и просто возвращал канал, начинающийся с null. Ничто не привело к желаемому поведению.


person Ran Lottem    schedule 12.08.2019    source источник


Ответы (1)


Если ваш someCallback() не является асинхронным и / или вы не захотите использовать его в будущем, я бы не стал реализовывать здесь новый оператор. Простая ванильная функция высшего порядка отлично справится с вашими потребностями.

function withLogging<A extends unknown[], C>(
  cb: (this: C, ...args: A) => void
) {
  return function(this: C, ...args: A) {
    console.log("before");
    cb.call(this, ...args);
    console.log("after");
  };
}

// snip

function someCallback() {
    console.log('Hello!');
}

someObs$.tap(withLogging(someCallback)); // before, Hello!, after for each pushed element
person Madara's Ghost    schedule 12.08.2019
comment
Это работает так, как задумано, и его гораздо проще понять, чем то, что я пробовал. Спасибо! - person Ran Lottem; 12.08.2019
comment
Последующие действия: если cb возвращает наблюдаемое, могу ли я проверить это, а затем pipe(tap(log))) вместо того, чтобы вести журнал после обратного вызова? Это позволит мне измерить время для всего асинхронного процесса, а не только для вызова функции. - person Ran Lottem; 12.08.2019
comment
Звучит не слишком сложно реализовать, хотя я признаю, что мой rx очень ржавый. - person Madara's Ghost; 12.08.2019