Why would you ever call .call() on Observable functions?

不打扰是莪最后的温柔 提交于 2019-12-01 04:13:21

To understand it, first you can have a look at the predefined JavaScript function method "call":

var person = {
    firstName:"John",
    lastName: "Doe",
    fullName: function() {
        return this.firstName + " " + this.lastName;
    }
}
var myObject = {
    firstName:"Mary",
    lastName: "Doe",
}
person.fullName.call(myObject);  // Will return "Mary Doe"

The reason of calling "call" is to invoke a function in object "person" and pass the context to it "myObject".

Similarly, the reason of this calling "call" below:

const inputValues$ = _do.call(this._valueChanges, value => {
  this._userInput = value;
  if (this.editable) {
    this._onChange(value);
  }
});

is providing the context "this._valueChanges", but also provide the function to be called base on that context, that is the second parameter, the anonymous function

value => {
  this._userInput = value;
  if (this.editable) {
    this._onChange(value);
  }
}

In the example that you're using:

  • this._valueChanges is the Input Event Observerable

  • The _do.call is for doing some side affects whenever the event input happens, then it returns a mirrored Observable of the source Observable (the event observable)

UPDATED Example code: https://plnkr.co/edit/dJNRNI?p=preview

About the do calling:

You can call it on an Observable like this:

const source = Rx.Observable.of(1,2,3,4,5);
const example = source
.do(val => console.log(`BEFORE MAP: ${val}`))
.map(val => val + 10)
.do(val => console.log(`AFTER MAP: ${val}`));
const subscribe = example.subscribe(val => console.log(val));

In this case you don't have to pass the first parameter as the context "Observable".

But when you call it from its own place like you said, you need to pass the first parameter as the "Observable" that you want to call on. That's the different.

as @Fan Cheung mentioned, if you don't want to call it from its own place, you can do it like:

const inputValues$=this._valueChanges.do(value=>{
  this._userInput = value;
  if (this.editable) {
    this._onChange(value);
  }
})

My personal opinion is that they were using this for RxJS prior 5.5 which introduced lettable operators. The same style is used internally by Angular. For example: https://github.com/angular/angular/blob/master/packages/router/src/router_preloader.ts#L91.

The reason for this is that by default they would have to patch the Observable class with rxjs/add/operators/XXX. The disadvantage of this is that some 3rd party library is modifying a global object that might unexpectedly cause problems somewhere else in your app. See https://github.com/ReactiveX/rxjs/blob/master/doc/lettable-operators.md#why.

You can see at the beginning of the file that they import each operator separately https://github.com/ng-bootstrap/ng-bootstrap/blob/master/src/typeahead/typeahead.ts#L22-L25.

So by using .call() they can use any operator and still avoid patching the Observable class.

I suppose

const inputValues$ = _do.call(this._valueChanges, value => {
  this._userInput = value;
  if (this.editable) {
    this._onChange(value);
  }
}); 

is equivalent to

const inputValues$=this._valueChanges.do(value=>{
 this._userInput = value;
  if (this.editable) {
    this._onChange(value);
  }
})

In my opinion it's not an usual pattern(I think it is the same pattern but written in different fashion) for working with observable. _do() in the code is being used as standalone function take a callback as argument and required to be binded to the scope of the source Observable

https://github.com/ReactiveX/rxjs/blob/master/src/operator/do.ts

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!