角度如何等待订阅

Jon*_*Doe 13 javascript typescript angular

我是 Angular 应用程序的新手。我不明白究竟是如何subscribe工作的。我目前的阻碍是我不明白为什么在console.log("B")之前执行console.log("A"),从而呈现空数组的结果(请参阅console输出链接)。

我试图将所有代码放在一个函数中async/await以等待该函数。我不明白为什么它不起作用。

在这种情况下等待订阅的最佳方式是什么?

console.log("B")必须后执行console.log("A")

this._roleService.getRoleTypes(this.token).subscribe(
    response => {
        if(response.status != "error" && response.code != 400){
            let _roleTypes:Array<RoleType> = new Array<RoleType>(); 
            _roleTypes = new Array<RoleType>();
            response.data.forEach(rt => {
                let roleType:RoleType = new RoleType(
                    rt.id,
                    rt.name
                );
                _roleTypes.push(roleType);
            });
            console.log("A");
            console.log(_roleTypes);
            this.roleTypes = _roleTypes;
        }
        else{
            this._loginService.destroySession();
        }
    },error => {
        this.errorMessage = <any>error;
        if(this.errorMessage != null){
            console.log(this.errorMessage);
            alert("Petition Error");
        }
    }
);
console.log("B");
console.log(this.roleTypes);
Run Code Online (Sandbox Code Playgroud)

Sun*_*nny 14

您可以使用 toPromise 方法实现此目的。这也是处理异步操作的好方法。只需删除订阅并添加此方法,并在调用此方法的方法中添加 async 关键字。

例子-

 const response = await this._roleService.getRoleTypes(this.token).toPromise();
Run Code Online (Sandbox Code Playgroud)

所以,现在你会先得到 console.log("A") 然后是 console.log("B")。

  • 这是一个很好的答案。我对此投双票。我很惊讶没有人将其标记为答案。这绝对等待订阅。 (3认同)

Cha*_*lie 13

如果您需要同步执行代码,则应使用 async/await。将您的订阅代码包装在一个返回承诺的函数中。

async getRolestypes(): Promise<Array<RoleType>> {

   return new Promise((resolve, reject) => {

     this._roleService.getRoleTypes(this.token).subscribe(
       response => {
         if(response.status != "error" && response.code != 400){
          let _roleTypes:Array<RoleType> = new Array<RoleType>(); 
          _roleTypes = new Array<RoleType>();
          response.data.forEach(rt => {
            let roleType:RoleType = new RoleType(
                rt.id,
                rt.name
            );
            _roleTypes.push(roleType);
           });
          console.log("A");
          console.log(_roleTypes);
          resolve(_roleTypes);
       }
       else{
           this._loginService.destroySession();
           reject('not a good response')
       }
       },error => {
        this.errorMessage = <any>error;
        if(this.errorMessage != null){
           reject(this.errorMessage);
        }
      }
    );


  })


}


this.roleTypes = await getRolestypes();
console.log(this.roleTypes);
Run Code Online (Sandbox Code Playgroud)


Kap*_*ash 8

您可能知道,订阅用于处理异步方法调用。因此,只有当异步方法返回其结果时(例如在 http 调用之后),才会执行 subscribe() 方法内的代码。

在等待异步响应时,程序继续执行以下代码。这就是异步调用的目标!

这就是为什么 yourconsole.log('B')在 your 之前执行console.log('A')

这是一个例子:

this.myservice.asyncCall().subscribe( (result) => {
   // wait for the async response
   console.log('I get some data from asyncCall()');
});
// sync code executed, even if the previous async call doesn't respond anything
console.log('Code executed after the subscription. But not waiting for it to respond');
Run Code Online (Sandbox Code Playgroud)

如果您想要console.log('B'),您必须将其移至您的订阅函数中(在 else 语句之后)。您还可以从该位置调用方法,具体取决于您要查找的目的。

.map()你也可以看一下方法。这允许您在订阅方法中处理检索到的响应之前对其进行编辑(向其添加一些数据、转换它、记录或任何内容)。


Sal*_*ani 5

上面的@sunny 答案是我的首选。但toPromise在 RxJs 7 中已被弃用,并且在 RxJs 8 发布时可能不会出现。所以新的方式是:

import { lastValueFrom } from 'rxjs';

const roleTypes$ = this._roleService.getRoleTypes(this.token);
const response = await lastValueFrom(roleTypes$);
Run Code Online (Sandbox Code Playgroud)