Angular中如何等待Subscribe执行?异步执行顺序问题求助
解决Angular中subscribe异步导致的执行顺序问题
Hey there! 我来帮你理清楚这个问题的根源,以及怎么解决它~
为什么会出现"B"先于"A"执行?
这里的核心问题是Observable的订阅操作是异步的:
- 当你调用
subscribe()时,浏览器会先把这个异步HTTP请求挂起,继续执行后面的同步代码(也就是你的console.log("B")和打印this.roleTypes)。 - 只有当服务器返回数据、异步请求完成后,才会触发
subscribe里的回调函数,执行console.log("A")和数据处理逻辑。 - 这就导致
this.roleTypes还没被赋值时,你就打印了它,自然是空数组。
解决方案一:把依赖代码放到subscribe回调内部(最简单直接)
既然订阅完成后才会执行回调里的逻辑,那把需要等待订阅结果的代码直接移到回调内部,放在this.roleTypes = _roleTypes之后就行。这样就能保证顺序:
this._roleService.getRoleTypes(this.token).subscribe( response => { if(response.status != "error" && response.code != 400){ let _roleTypes:Array<RoleType> = 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; // 把需要在订阅完成后执行的代码移到这里 console.log("B"); console.log(this.roleTypes); } else { this._loginService.destroySession(); } }, error => { this.errorMessage = <any>error; if(this.errorMessage != null){ console.log(this.errorMessage); alert("Petition Error"); } } );
解决方案二:用async/await结合RxJS的Promise转换
如果你更习惯async/await的写法,需要把Observable转换成Promise(因为await只能处理Promise)。RxJS在Angular 12+推荐用firstValueFrom或lastValueFrom来做转换(代替旧版的toPromise):
// 定义一个async函数 async loadRoleTypes() { try { // 把Observable转成Promise,await等待请求完成 const response = await firstValueFrom(this._roleService.getRoleTypes(this.token)); if(response.status != "error" && response.code != 400){ let _roleTypes:Array<RoleType> = 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(); } // 这里的代码会在请求完成后执行 console.log("B"); console.log(this.roleTypes); } catch(error) { // 捕获请求错误,替代原来的error回调 this.errorMessage = <any>error; if(this.errorMessage != null){ console.log(this.errorMessage); alert("Petition Error"); } } } // 调用这个async函数 this.loadRoleTypes();
为什么你之前用async/await没效果?因为你可能直接await了subscribe()的结果,但subscribe()返回的是Subscription对象,不是Promise,所以await根本起不到等待的作用,必须先把Observable转成Promise才行。
总结
- 方案一适合简单场景,代码改动最小;
- 方案二更适合需要用
async/await组织复杂异步逻辑的场景。
两种方式都能保证console.log("B")在console.log("A")之后执行,并且打印出正确的this.roleTypes值。
内容的提问来源于stack exchange,提问作者Jon Doe
相关产品推荐
相关产品推荐

