在 Observable 中调用 Promise

Posted

技术标签:

【中文标题】在 Observable 中调用 Promise【英文标题】:Call Promise inside Observable 【发布时间】:2019-07-10 10:06:22 【问题描述】:

我必须在另一个 API 调用(返回 Observable)之后进行 API 调用(返回 Promise)。

userService.getAuthUser() 返回一个Observable

userService.updateUser() 返回一个Promise

我可以通过将updateUser() 放入getAuthUser() 来实现这一点

this.userService.getAuthUser().subscribe((res) =>
  this.userService.updateUser(res.id, <User>(
    name: 'Sample Name'
  )).then((res) =>
    console.log('update user success');
  ).catch((err) => 
    console.log('update user failed');
  )
,
(err) => 
  console.log('get auth user failed');
)

但我觉得这样做不太好,有点回调地狱,还有更好的方法吗?

注意:我无法将 userService.updateUser() 更改为 Observable

【问题讨论】:

您依赖于 observable 为下一个 updateUser() 部分返回的值。所以这很好。如果您想拥有更简洁的代码,请创建另一个方法来使用参数更新用户并在 subscribe 中调用它 您可以将 Observable 转换为 Promise 并链接 Promise。 ***.com/questions/36777284/…***.com/a/54710279/495157 您还可以将 Promise 转换为 Observable ***.com/questions/39319279/… ***.com/questions/37771855/… 【参考方案1】:

有几种方法可以实现这一点。

一种方法如果您希望 getAuthUser 流保持活动状态,则可以使用 from operator 将 promise 转换为 observable。这将允许您继续流并对整个流的错误/处理成功做出反应。您还可以使用catchError operator 指定流中对特定错误做出反应的位置。

类似于:

this.userService.getAuthUser()
  .pipe(
    catchError(err => 
      // throw an error how you like, see the 'throw' operator
      // can also create with other operators like 'of'
    ),
    switchMap(auth =>
      from( // will detect promise and return observable
        this.userService.updateUser(res.id, <User>(
          name: 'Sample Name'
        ))
      )
    ),
    catchError(err => 
      // throw an error how you like, see the 'throw' operator
      // can also create with other operators like 'of'
    )

  ).subscribe(
    (res) => 
      // if you were expecting data at this point
    , (err) => 
      // if you threw the error
    
  )

另一种方法如果您不需要流保持活动状态,您可以使用.toPromise() 将 Observable 从第一个流转换为 Promise。从这里开始,您有两条典型的路径可供遵循。你可以使用async/await,或者只是链接promise。

对于异步等待,类似于:

// the method will have to be async for await to not show errors

const authUser = await this.userService.getAuthUser().toPromise();

// determine if you should update
// if so

const updateUserResult = await this.userService.updateUser(res.id, <User>(name: 'Sample Name'));

【讨论】:

对于catchError 部分,它显示了一些错误Argument of type '(err: any) =&gt; void' is not assignable to parameter of type '(err: any, caught: Observable&lt;void&gt;) =&gt; ObservableInput&lt;&gt;'. Type 'void' is not assignable to type 'ObservableInput&lt;&gt;'.,我必须使用throw 哪个 catchError 部分(或两者)?抱歉,给出“流”示例有点粗略。我很乐意更新您的发现 实际上,我都抛出了catchError(err =&gt; console.log(err) throw err; 之类的错误,否则 IDE 正在崩溃 哦,明白了,“返回可观察的静止图像”部分。 throw 是一种选择,但任何可以创建新 observable 的方式都是有效的。一个用例是捕获错误,在那里处理它,并将流更改为新的 observable,以便下游效果在需要时可以做出不同的反应。【参考方案2】:
import  flatMap, map, catchError  from 'rxjs/operators';
import  of, from  from 'rxjs';

this.userService
  .getAuthUser()
  .pipe(
    flatMap(
      ( id ) =>
        from(this.userService.updateUser(id)).pipe(
          map(response => 
            console.log('update user success');
            return response;
          ),
          catchError(error => 
            console.log('update user failed');
            return of(error);
          )
        ),
      catchError(error => 
        console.log('get auth user failed');
        return of(error);
      )
    )
  )
  .subscribe();

【讨论】:

以上是关于在 Observable 中调用 Promise的主要内容,如果未能解决你的问题,请参考以下文章

完全没有在 Observable 订阅方法中被调用

Angular - 在另一个组件中使用 observable(在异步数据调用中获取值)

如何在redux-observable中同时进行多个ajax调用?

React redux-observable:以史诗般的方式进行顺序 API 调用

KnockoutJS - 我们可以为 CSS 更新调用 Observable 函数吗

如何在 React 中正确地进行 GET 调用,返回一个 observable(类似于 Angular 中的方法而不使用 Promise)?