Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/393.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 如何以更干净的方式编写嵌套订阅?_Javascript_Angular_Typescript_Rxjs - Fatal编程技术网

Javascript 如何以更干净的方式编写嵌套订阅?

Javascript 如何以更干净的方式编写嵌套订阅?,javascript,angular,typescript,rxjs,Javascript,Angular,Typescript,Rxjs,我是RxJS新手,我想学习如何以干净的方式使用它编写代码。我有嵌套订阅,我试图重写它,但没有结果 firstMethod() { this.testMethod(name) console.log(this.currentPerson) } testMethod() { this.myService.search(name).subscribe(response => { if(result) { this.currentPerson = result

我是RxJS新手,我想学习如何以干净的方式使用它编写代码。我有嵌套订阅,我试图重写它,但没有结果

firstMethod() {
  this.testMethod(name)
  console.log(this.currentPerson)
}

testMethod() {
  this.myService.search(name).subscribe(response => {
    if(result) {
      this.currentPerson = result
    } else {
        this.myService.create(name).subscribe(result => {
          const person = {id: result.id, name: name}
          this.currentPerson = person
        })
      }
   })
}
不幸的是,尽管代码很凌乱,“else”后面的某个部分有问题,因为console.log显示未定义。 如何修复它的任何提示?

使用返回一个新的基于结果值的可观察值,如下所示:

this.myService.searchname 管 switchMapresult=>{ 返回iif =>结果, 结果, this.myService.createname.pipemap{id}=>{id,name} } .subscribeperson=>{ } 或者可选地:

this.myService.searchname 管 switchMapresult=>{ 若结果返回结果; 否则this.myService.createname.pipemap{id}=>{id,name}; } .subscribeperson=>{ } 使用返回基于结果值的新可观察值,如下所示:

this.myService.searchname 管 switchMapresult=>{ 返回iif =>结果, 结果, this.myService.createname.pipemap{id}=>{id,name} } .subscribeperson=>{ } 或者可选地:

this.myService.searchname 管 switchMapresult=>{ 若结果返回结果; 否则this.myService.createname.pipemap{id}=>{id,name}; } .subscribeperson=>{ }
为了有效地处理嵌套订阅,您应该使用其中一个,它可以为您带来一些好处:

将传入值映射到另一个可观察值 订阅它,因此它的值被发送到流中 自动管理从这些内部订阅取消订阅 在这种情况下,switchMap是一个很好的选择,因为它一次只允许一个内部订阅,所以每当调用myService.searchname时,就会为myService.createname创建一个新的内部订阅,并自动取消订阅上一个订阅

@拉菲·海尼格的回答是一个很好的例子

请注意.pipe的用法。您可以使用管道操作符定义对可观察输出的转换,而无需实际订阅。 我建议您不要订阅testMethod,而是返回一个可观察的。另外,让我们为testMethod提供一个更有意义的名称,以供进一步讨论:getPerson

getPerson(name: string): Observable<Person> {
  return this.myService.search(name).pipe(
    switchMap(result => {
      return iif(
        () => result,
        of(result),
        this.myService.create(name).pipe(
          map(({ id }) => ({ id, name }))
        )
      )
    }),
    tap(person => this.currentPerson = person)
  );
}
未定义的原因是因为代码是异步的。执行第2行,然后立即执行第3行,但异步工作尚未完成,因此尚未设置this.currentPerson

由于我们的getPerson方法现在返回一个可观察的,我们可以订阅并在订阅中执行您的console.log:

1  firstMethod() {
2    this.getPerson(name).subscribe(
3       () => console.log(this.currentPerson)
4    )
5  }
为了简化,我们甚至不再需要这个.currentPerson,因为这个人是通过流发出的

1  firstMethod() {
2    this.getPerson(name).subscribe(
3       person => console.log(person)
4    )
5  }
既然你想

了解如何以干净的方式使用它编写代码

我认为最干净的方法可能是将你的个人结果定义为一个可观察的结果,并抛弃这个.currentPerson

现在你有了这个.person$,可以订阅它,它的当前值总是person。无需手动更新此.currentPerson

嗯。。。几乎我们需要考虑当搜索词发生变化时会发生什么。

假设搜索词名称来自表单控件输入

当使用输入值时,它是一个可观察的来源,因此我们可以从搜索词中定义我们的person$:

searchTerm$ = this.searchInput.valueChanges();

person$ = this.searchTerm$.pipe(
  switchMap(searchTerm => this.getPerson(searchTerm))
);

getPerson(name: string): Observable<Person> {
  return this.myService.search(name).pipe(
    switchMap(result => {
      return iif(
        () => result,
        of(result),
        this.myService.create(name).pipe(
          map(({ id }) => ({ id, name }))
        )
      )
    })
  );
}

我知道这有点冗长,但我希望您了解如何使用可管道运算符转换输出,以及如何定义一个可观察对象与另一个可观察对象。

要有效处理嵌套的订阅,您应该使用其中一个,这对您有好处:

将传入值映射到另一个可观察值 订阅它,因此它的值被发送到流中 自动管理从这些内部订阅取消订阅 在这种情况下,switchMap是一个很好的选择,因为它一次只允许一个内部订阅,所以每当调用myService.searchname时,就会为myService.createname创建一个新的内部订阅,并自动取消订阅上一个订阅

@拉菲·海尼格的回答是一个很好的例子

请注意.pipe的用法。您可以使用管道操作符定义对可观察输出的转换,而无需实际订阅。 我建议您不要订阅testMethod,而是返回一个可观察的。另外,让我们为testMethod提供一个更有意义的名称,以供进一步讨论:getPerson

getPerson(name: string): Observable<Person> {
  return this.myService.search(name).pipe(
    switchMap(result => {
      return iif(
        () => result,
        of(result),
        this.myService.create(name).pipe(
          map(({ id }) => ({ id, name }))
        )
      )
    }),
    tap(person => this.currentPerson = person)
  );
}
未定义的原因是因为代码是异步的。执行第2行,然后立即执行第3行,但异步工作尚未完成,因此尚未设置this.currentPerson

由于我们的getPerson方法现在返回一个可观察的,我们可以订阅并在订阅中执行您的console.log:

1  firstMethod() {
2    this.getPerson(name).subscribe(
3       () => console.log(this.currentPerson)
4    )
5  }
为了简化,我们甚至不再需要这个.currentPerson,因为这个人是通过流发出的

1  firstMethod() {
2    this.getPerson(name).subscribe(
3       person => console.log(person)
4    )
5  }
既然你想

了解如何以干净的方式使用它编写代码

我认为最干净的方法可能是将你的个人结果定义为一个可观察的结果,并抛弃这个.currentPerson

现在你有了这个.person$,可以订阅它,它的当前值总是person。无需手动更新此.currentPerson

嗯。。。几乎我们需要考虑当搜索词发生变化时会发生什么。

假设搜索词名称来自表单控件输入

当使用输入值时,它是一个可观察的来源,因此我们可以从搜索词中定义我们的person$:

searchTerm$ = this.searchInput.valueChanges();

person$ = this.searchTerm$.pipe(
  switchMap(searchTerm => this.getPerson(searchTerm))
);

getPerson(name: string): Observable<Person> {
  return this.myService.search(name).pipe(
    switchMap(result => {
      return iif(
        () => result,
        of(result),
        this.myService.create(name).pipe(
          map(({ id }) => ({ id, name }))
        )
      )
    })
  );
}

我知道这有点啰嗦,但我希望您了解如何使用可管道运算符转换输出,以及如何定义一个可观察对象与另一个可观察对象。

检查检查尽管上述答案对于共享示例是正确的,但请注意您正在尝试做的事情。SwitchMap将自动取消订阅上一个可观察对象,并订阅给定控制流的另一个可观察对象。在共享的示例中,这似乎是您在更新单个属性时尝试执行的操作。尽管如此,在某些情况下,您可能希望保持每个可观察对象,例如,合并映射会更好。看看@BizzyBob答案。这是非常完整的。虽然上面的答案对于共享的示例是正确的,但要注意你正在尝试做什么。SwitchMap将自动取消订阅上一个可观察对象,并订阅给定控制流的另一个可观察对象。在共享的示例中,这似乎是您在更新单个属性时尝试执行的操作。尽管如此,在某些情况下,您可能希望保持每个可观察对象,例如,合并映射会更好。看看@BizzyBob答案。差不多完成了