繁体   English   中英

如何从角度中的单个函数返回订阅和承诺?

[英]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" />

这是当前的场景,我们无法将服务函数中的进度变量访问到调用服务函数的主机组件中。

一种方法是,我们可以在宿主组件中获取订阅服务功能,并且可以不断获取进度值。 但是怎么样?

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

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

我想为每次调用保留订阅变量的本地范围。

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

你应该从你的服务中返回一个 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
        })
    }

您可以将标头传递给您的 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();
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM