Observable 和 xhr.upload.onprogress 事件

Кач*_*фей 5 rxjs typescript angular

我有两个服务。

1) UploadService- 将文件通过 ajax 发送到服务器,并获取并存储进度值(在 xhr.upload.onprogress 事件处理程序中)

2)SomeOtherService使用 DOM,从第一个服务获取进度值,将其显示在 Bootstrap 进度条上。

因为,xhr.upload.onprogress是异步的 - 我Observable在第一个服务中使用:

constructor () {
    this.progress$ = new Observable(observer => {
        this.progressObserver = observer
    }).share();
}

private makeFileRequest (url: string, params: string[], files: File[]): Promise<any> {
    return new Promise((resolve, reject) => {
        let formData: FormData = new FormData(),
            xhr: XMLHttpRequest = new XMLHttpRequest();

        for (let i = 0; i < files.length; i++) {
            formData.append("uploads[]", files[i], files[i].name);
        }

        xhr.onreadystatechange = () => {
            if (xhr.readyState === 4) {
                if (xhr.status === 200) {
                    resolve(JSON.parse(xhr.response));
                } else {
                    reject(xhr.response);
                }
            }
        };

        xhr.upload.onprogress = (event) => {
            this.progress = Math.round(event.loaded / event.total * 100);

            this.progressObserver.next(this.progress);
        };

        xhr.open('POST', url, true);
        xhr.send(formData);
    });
}
Run Code Online (Sandbox Code Playgroud)

Insise 第二个服务,我订阅了这个观察者:

this.fileUploadService.progress$.subscribe(progress => {
    this.uploadProgress = progress
});

this.fileUploadService.upload('/api/upload-file', [], this.file);
Run Code Online (Sandbox Code Playgroud)

现在我的问题:

该代码不起作用。在第二次服务中,我仅获得一次观察值,100%。

但是如果我插入(是的,带有空的回调主体)

setInterval(() => {
}, 500);
Run Code Online (Sandbox Code Playgroud)

在 makeFileRequest 方法中 - 我将每 500 毫秒在第二个服务中获取进度值。

private makeFileRequest (url: string, params: string[], files: File[]): Promise<any> {
    return new Promise((resolve, reject) => {
        let formData: FormData = new FormData(),
            xhr: XMLHttpRequest = new XMLHttpRequest();

        for (let i = 0; i < files.length; i++) {
            formData.append("uploads[]", files[i], files[i].name);
        }

        xhr.onreadystatechange = () => {
            if (xhr.readyState === 4) {
                if (xhr.status === 200) {
                    resolve(JSON.parse(xhr.response));
                } else {
                    reject(xhr.response);
                }
            }
        };

        setInterval(() => {
        }, 500);

        xhr.upload.onprogress = (event) => {
            this.progress = Math.round(event.loaded / event.total * 100);

            this.progressObserver.next(this.progress);
        };

        xhr.open('POST', url, true);
        xhr.send(formData);
    });
}
Run Code Online (Sandbox Code Playgroud)

那是什么?为什么会这样?我如何在onprogress没有 setInterval 的情况下正确使用 Observable 和事件?

UPD:在 Thierry Templier 里面回答之后

this.service.progress$.subscribe( data => { 
    console.log('progress = '+data); 
}); 
Run Code Online (Sandbox Code Playgroud)

我得到了正确的值,但该值没有在模板内动态更新,仅再次 100%。

Thi*_*ier 3

我没有完整的代码,所以很难给你一个准确的答案。

事实上,你说“在第二次服务中,我只获得一次观察值,100%”。让我觉得应该和promise的使用有关。事实上,Promise 可以一次性解决或拒绝。不支持与可观察量相反的多个事件。

如果您可以将代码与 plunkr 一起发布,我将能够对其进行调试,以便为您提供更准确的答案。

编辑

我创建了一个plunkr(http://plnkr.co/edit/ozZqbxIorjQW15BrDFrg?p=preview)来测试您的代码,看起来它可以工作。通过将承诺更改为可观察的,我可以获得更多进度提示。

makeFileRequest(url: string, params: string[], files: File[]): Observable> {
  return Observable.create(observer => {
    let formData: FormData = new FormData(),
        xhr: XMLHttpRequest = new XMLHttpRequest();

    for (let i = 0; i < files.length; i++) {
        formData.append("uploads[]", files[i], files[i].name);
    }

    xhr.onreadystatechange = () => {
        if (xhr.readyState === 4) {
            if (xhr.status === 200) {
                observer.next(JSON.parse(xhr.response));
                observer.complete();
            } else {
                observer.error(xhr.response);
            }
        }
    };

    xhr.upload.onprogress = (event) => {
        this.progress = Math.round(event.loaded / event.total * 100);

        this.progressObserver.next(this.progress);
    };

    xhr.open('POST', url, true);
    xhr.send(formData);
  });
}
Run Code Online (Sandbox Code Playgroud)

这是我的痕迹:

app.component.ts:18 progress = 21
app.component.ts:18 progress = 44
app.component.ts:18 progress = 71
app.component.ts:18 progress = 100
Run Code Online (Sandbox Code Playgroud)

有了承诺,我只得到两条痕迹