为何从Subject(Observable)转换的Promise未达预期?第二个Promise失效?
问题分析:文件上传代码中第二个Promise无输出的原因
先看你这段代码的核心问题:
public upload(): Promise<any> { return (this.loader.file as Promise<File>) .then(file => { const uploadImageUrl$: Subject<string> = new Subject<string>();; this.uploadImageService.uploadFile(file).subscribe( data => { uploadImageUrl$.next(this.uploadImageService.getImageUrlByResponse(data)); }); uploadImageUrl$.subscribe(console.log); //return url return uploadImageUrl$.toPromise(); }) .then(url => { console.log(url); //doesn't work return {default: url}; }); }
问题根源
你这里用Subject.toPromise()的时候,Subject从来没有发出complete信号。RxJS里的toPromise()规则是:它会等待Observable(包括Subject)发出complete事件,才会把最后一个next的值作为Promise的resolve结果返回;如果Observable一直不complete,Promise就会一直处于pending状态,后面的then(url => {...})自然永远不会执行,所以你看不到console.log(url)的输出。
另外,其实你完全没必要用Subject来做中间转换,这属于多此一举,反而引入了额外的问题。
修复方案
有两种方式可以解决这个问题:
方案1:给Subject发送complete信号
在调用next之后手动调用complete(),让Promise能正常resolve:
public upload(): Promise<any> { return (this.loader.file as Promise<File>) .then(file => { const uploadImageUrl$: Subject<string> = new Subject<string>(); this.uploadImageService.uploadFile(file).subscribe( data => { const url = this.uploadImageService.getImageUrlByResponse(data); uploadImageUrl$.next(url); uploadImageUrl$.complete(); // 关键:发送complete信号 }); uploadImageUrl$.subscribe(console.log); return uploadImageUrl$.toPromise(); }) .then(url => { console.log(url); // 现在能正常输出了 return {default: url}; }); }
方案2:直接将Observable转为Promise(更推荐)
既然uploadFile本身就是Observable,直接用firstValueFrom或者lastValueFrom(RxJS 7+推荐的API,替代旧的toPromise())来转换,省去Subject的中间层:
import { firstValueFrom } from 'rxjs'; public async upload(): Promise<any> { const file = await this.loader.file as Promise<File>; const data = await firstValueFrom(this.uploadImageService.uploadFile(file)); const url = this.uploadImageService.getImageUrlByResponse(data); console.log(url); return {default: url}; }
用async/await语法会让代码更简洁易读,也避免了嵌套的then回调。
内容的提问来源于stack exchange,提问作者prolina
相关产品推荐
相关产品推荐

