如何 return 从 angular 中的单个函数订阅和承诺?

How to return subscription and promise from single function in angular?

我正在开发一个 angular 项目,其中实现了文件上传功能。 我已经创建了一个上传服务并在其中创建了一个用于上传文件的功能

service.ts :

upload(file: File){
  return new Promise(resolve=>{
    var file = file;
    bucket.upload(file).on("httpUplaodprogress", (progress)=>{
        const percent = progress.percent

        -->  Here I want to emit this percent value from this function. and want to get it where it is from called.


    }).send(response =>{
      response.error ? reject(response.err);
      resolve(response);
    })
  })
}

现在很多地方都在用这个上传服务。

例如:

uploadComponent.ts :

progress:number = 0;

constructor(private uploadService: UploadService) {}

handleFileInput(file){
    this.uploadService.upload(file).then(result=>{
       result ? show success msg for file uplaod success : show error

       ==> I want to subscribe service's upload function's progress variable 
           here for assign that value into this host component's progress variable which is 
           bind with progressbar copmponent.
   
    })
}

uploadComponent.html

<progressbar [progress]="progress" />

在当前情况下,我们无法从服务函数访问进度变量到调用服务函数的主机组件中。

一种方法是,我们可以将订阅服务功能获取到宿主组件中,并且可以持续获取进度值。但是如何?

因为服务功能已经return承诺。我如何在 promise 中使用订阅并将其订阅到主机组件中。

我也考虑过将全局订阅变量订阅到服务中并将其订阅到主机组件中。但从多个地方上传文件并显示进度条时可能会导致问题。

我希望每次调用都将订阅变量的作用域保持在本地。

如果有人知道如何从 promise 函数广播值并从调用它的地方接收主机函数.. 那么请回复这个。对我很有帮助。

你可以通过headers给你http调用订阅进度

reportProgress: true,
observe: 'events'

在你上传组件

yourservice.subscribe((e: HttpEvent<any>) => {
          switch (e.type) {
            case HttpEventType.Sent:
              break;
            case HttpEventType.ResponseHeader:
              break;
            case HttpEventType.UploadProgress:
              this.progress = Math.round(e.loaded / e.total * 100);
              break;
            case HttpEventType.Response:
              this.progress = -1;
          }
    });

如果你愿意,你可以选择实施一个行为主题来实现这一点 在您的 service.ts 中将 processPercentage 声明为行为主体

const percent = progress.percent;
this.processPercentage.next(percent);

在你的uploadComponent.ts

subscription:Subscription;
constructor(private uploadService: UploadService,private service:Service) {}
ngOnInit(){
 this.getProgress();
}

getProgress(){
 this.subscription = 
 this.service.processPercentage.asObservable().susbcribe((progress) => {
  this.progress = progress;
  console.log(this.progress);
  // You can bind to your progressbar from here 
 });
}

ngOnDestroy(){
 this.subscription.unsubscribe();
}

您应该 return 从您的服务中获取 Observable 而不是 Promise。

UploadService

// note that BucketUploadResponse is an interface I made up
upload(file: File): Promise<BucketUploadResponse> {
     // delegate to our Observable implementation and convert to promise
     return this.upload$(file).toPromise();
}

// note that BucketUploadResponse is an interface I made up
upload$(file: File): Observable<number | BucketUploadResponse> {
        return new Observable<number>((subscriber) => {
            bucket
                .upload(file)
                .on('httpUplaodprogress', (progress) => {
                    const percent = progress.percent;
                    // emit progress
                    subscriber.next(percent);
                })
                .send((response) => {
                    if (response.error) {
                        // error out
                        subscriber.error(response.error);
                    } else {
                        // emit response as last item to keep old contract
                        subscriber.next(response);
                        subscriber.complete();
                    }
                });

            return () => {
                // called when no subscription is left. You could abort the upload here for example
            };
        });
    }

在消费组件中,您可以订阅 Observable:

    progress:number = 0;
    
    private uploadSubscription?: Subscription;

    constructor(private uploadService: UploadService) {}

    handleFileInput(file){
        this.progress = 0;
        // unsubscribe from an existing upload
        this.uploadSubscription?.unsubscribe();
        this.uploadSubscription = this.uploadService.upload(file).subscribe((progress) => {
            if (typeof progress === 'number') {
                this.progress = progress;
            } else {
                // handle BucketUploadResponse if required
            }
        }, () => {
            // complete, show success message
        }, (error) => {
            // error, show error message
        })
    }