简体   繁体   English

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

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

I am working on one angular project in which I have file upload feature is implemented.我正在开发一个 angular 项目,其中实现了文件上传功能。 I have created one upload service and make one function inside it for upload file我创建了一个上传服务并在其中创建了一个用于上传文件的功能

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);
    })
  })
}

Now this upload service is used at many place.现在很多地方都在使用这个上传服务。

Eg :例如:

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" />

This is current scenario where we can't access progress variable from service function into host component where service function is called.这是当前的场景,我们无法将服务函数中的进度变量访问到调用服务函数的主机组件中。

one way is that, we can get subscribe service function into host component and can progress value can continuously get.一种方法是,我们可以在宿主组件中获取订阅服务功能,并且可以不断获取进度值。 but how ?但是怎么样?

because service function already return promise.因为服务功能已经返回承诺。 how can I use subscription inside promise and subscribe it into host component.如何在 promise 中使用订阅并将其订阅到主机组件中。

I had also thought about global subscription variable into service and subscribe it into host component.我还考虑过将全局订阅变量加入服务并将其订阅到主机组件中。 but it can cause problem when upload file from multiple places and show progressbar.但是从多个地方上传文件并显示进度条时可能会导致问题。

I want to keep subscription variable's scope local for each call.我想为每次调用保留订阅变量的本地范围。

If anyone know about it, how to broadcast value from promise function and receive at host function from where it is called.. then please reply this.如果有人知道它,如何从承诺函数广播值并从它被调用的地方接收主机函数..然后请回复这个。 It's very helpful for me.这对我很有帮助。

Your should return an Observable from your service instead of a 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
            };
        });
    }

In the consuming component, you can subscribe to the Observable:在消费组件中,您可以订阅 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
        })
    }

You can pass headers to you http call to subscribe progress您可以将标头传递给您的 http 调用以订阅进度

reportProgress: true,
observe: 'events'

In you Upload Component在你上传组件

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;
          }
    });

OR或者

You have an option to implement a behavior subject to achieve this if you want In your service.ts declare processPercentage as behavior subject如果您愿意,您可以选择实施行为主题来实现这一点在您的 service.ts 中将 processPercentage 声明为行为主题

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

In your uploadComponent.ts在你的 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