baconjs / bacon.js

Functional reactive programming library for TypeScript and JavaScript

Home Page:https://baconjs.github.io

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Cannot use JS objects which throw on undefined property access

semmel opened this issue · comments

An example of such an "exotic" object is the Cross-Origin WindowProxy object. It throws when trying to access (i.e. getOwnProperty) any property other than the handful of allowed properties.

Observed behaviour:

Combining an observable of WindowProxy with any other observable will generate a DOM SecurityError ("Blocked a frame from accessing a cross-origin frame…")

Reason:

The implementation of combine calls isObservable on the stream value. isObservable is simply winProxy._isObservable which fails.

Solution:

Can't see any.
Switching to winProxy instanceof Observable from winProxy._isObservable would work, but that was in #639 deliberately introduced to support X-frame observables I guess.

Not understanding the code, I guess combine needs to do some dependency checks and therefore inspects the incoming stream values. So no way to remove that – at first glance – useless check.

Workaround:

Wrap/Unwrap "exotic" objects before injecting into/when extracting from bacon streams. E.g. use (Edit:) [windowProxy] an object wrapper {windowProxy} as stream value.

Edit:

You cannot wrap the "exotic" object in a simple Array, because that gets flattened internally and it's items inspected (._isObservable) as well.

Maybe another topic, but

I don't expect my array-type stream events being accessed in any way (here being iterated over) by the reactive stream library for internal purposes. 😮

I mean; isn't the deal, that I put my things into the stream, which conveys the things to my combiners and my consumers?

Demo:

On JSitor REPL

B.fromEvent(button, 'click')
    .map(() => open(
      "https://example.com", 
      "demo-popup", 
      "popup,width=200,height=200"
    ))
    //.map(_ => [_])   // Edit: NO workaround
    //.map(proxy => ({proxy}))  // workaround
    .delay(2000)  // wait for example.com to respond
    .combine(B.constant("foo"), pair)
    .onValue(([, foo]) => { console.log(foo); });