kefirjs / kefir

A Reactive Programming library for JavaScript
https://kefirjs.github.io/kefir/
MIT License
1.87k stars 97 forks source link

TypeError: this._emitValue is not a function #295

Open Macil opened 4 years ago

Macil commented 4 years ago

In a project that uses Kefir, I've seen a strange error show up yesterday in our client error logs. A single user hit this error a few dozen times in one session only. We haven't had anyone else ever hit this error, so it's pretty low priority for the project.

The stacktrace is very interesting to me. The error doesn't seem like something that should be possible. It implies that to-property.js's _onActivation method is being called on an object without an _emitValue method. Even if the application did something wrong like passing a non-stream to Kefir where a stream was expected, this seems like something that shouldn't be possible. But I don't understand the flow fully enough to be sure that this should be impossible. Maybe there's some kind of situation where it can happen if a property activates while a dependent stream is still being initialized.

TypeError: this._emitValue is not a function
File webpack:///./node_modules/kefir/dist/kefir.esm.js line 1005 col 12 in r._onActivation
this._emitValue(getInitial());
File webpack:///./node_modules/kefir/dist/kefir.esm.js line 264 col 14 in r._setActive
this._onActivation();
File webpack:///./node_modules/kefir/dist/kefir.esm.js line 520 col 12 in r._on
this._setActive(true);
File webpack:///./node_modules/kefir/dist/kefir.esm.js line 332 col 17 in r.onAny
return this._on(ANY, fn);
File webpack:///./node_modules/kefir/dist/kefir.esm.js line 970 col 20 in r._onActivation
this._source.onAny(this._$handleAny);
File webpack:///./node_modules/kefir/dist/kefir.esm.js line 264 col 14 in r._setActive
this._onActivation();
File webpack:///./node_modules/kefir/dist/kefir.esm.js line 520 col 12 in r._on
this._setActive(true);
File webpack:///./node_modules/kefir/dist/kefir.esm.js line 332 col 17 in r.onAny
return this._on(ANY, fn);
File webpack:///./node_modules/kefir/dist/kefir.esm.js line 970 col 20 in r._onActivation
this._source.onAny(this._$handleAny);
File webpack:///./node_modules/kefir/dist/kefir.esm.js line 264 col 14 in r._setActive
this._onActivation();
File webpack:///./node_modules/kefir/dist/kefir.esm.js line 520 col 12 in r._on
this._setActive(true);
File webpack:///./node_modules/kefir/dist/kefir.esm.js line 332 col 17 in r.onAny
return this._on(ANY, fn);
File webpack:///./node_modules/kefir/dist/kefir.esm.js line 970 col 20 in r._onActivation
this._source.onAny(this._$handleAny);
File webpack:///./node_modules/kefir/dist/kefir.esm.js line 264 col 14 in r._setActive
this._onActivation();
File webpack:///./node_modules/kefir/dist/kefir.esm.js line 520 col 12 in r._on
this._setActive(true);
File webpack:///./node_modules/kefir/dist/kefir.esm.js line 332 col 17 in r.onAny
return this._on(ANY, fn);
File webpack:///./node_modules/kefir/dist/kefir.esm.js line 1297 col 25 in we._onActivation
this._sources[_i].onAny(this._$handlers[_i]);
File webpack:///./node_modules/kefir/dist/kefir.esm.js line 264 col 14 in we._setActive
this._onActivation();
File webpack:///./node_modules/kefir/dist/kefir.esm.js line 307 col 12 in we._on
this._setActive(true);
File webpack:///./node_modules/kefir/dist/kefir.esm.js line 332 col 17 in we.onAny
return this._on(ANY, fn);
File webpack:///./node_modules/kefir/dist/kefir.esm.js line 2983 col 23 in r._onActivation
this._primary.onAny(this._$handlePrimaryAny);
File webpack:///./node_modules/kefir/dist/kefir.esm.js line 264 col 14 in r._setActive
this._onActivation();
File webpack:///./node_modules/kefir/dist/kefir.esm.js line 307 col 12 in r._on
this._setActive(true);
File webpack:///./node_modules/kefir/dist/kefir.esm.js line 323 col 17 in r.onValue
return this._on(VALUE, fn);
File ... line 33 col 8 in ...
.onValue(emitter);

Here's a simplified version of the application code where this is happening. The .onValue call at the bottom of the stack trace is the one here.

    const stopper = kefirStopper();
    const streamFromPromise = Kefir.fromPromise(somePromise);
    const someProperty = someMaybeAlreadyActivatedBus.filter(...).toProperty(() => null).map(...).map(...).map(...);
    Kefir.combine(
      [streamFromPromise, someProperty],
      (valueA, valueB) => valueA.concat(valueB)
    )
      .takeUntilBy(stopper)
      .onValue(emitter);

I checked that the project isn't doing something surprising like using different versions or instances of the Kefir library in a single project and then mixing streams from them.

(Kefir version 3.8.6)

mAAdhaTTah commented 4 years ago

I dunno what logger tool you're using, but if there's some way to capture the value of this when this error pops up, that would probably be really helpful to tracking it down. Because you're activating a Property, it's possible there's something downstream from emitter (whatever that happens to be) causing the issue.

I'm assuming you haven't been able to reproduce this yourself at all?