@sanex3339

Что за странное поведение у Observable в связке с xhr.upload.onprogress?

Слушайте мою историю.

Вожусь с ангуларом 2.

Сделал сервис, который аяксом отсылает файлы на сервер, заодно на событии xhr.upload.onprogress считает проценты и записывает в своё (сервиса) св-во.

Сделал еще другой сервис, который получает файлы из инпута формы, заливает их через первый сервис, а заодно и выводит состояние прогресса загрузки. Как видно, отвечает, в основном, за взаимодействие с вьюхой.

Ну разумеется, захотелось опробовать Observable, что бы за значением св-ва onprogress внутри 1-го сервиса (которое, напомню, обновляется асинхронно в эвенте onprogress), следить внутри 2-го сервиса и тут же красиво выводить в виде бутстраповского progressbar'а.

И вот тут то чудеса. Сначала код:

1-й сервис, который отправляет файлы аяксом, в нем создается 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);
        });
    }


2-й сервис, в котором следим за progress$ из 1-го сервиса:
this.fileUploadService.progress$.subscribe(progress => {
            this.uploadProgress = progress
        });

        this.fileUploadService.upload('/api/upload-file', [], this.file);


В общем при таком коде - как вы уже догадались, ничего не обновляется, совсем.

Стал смотреть, да выискивать причину. Сначала вынес this.progressObserver.next(this.progress); из эвента на уровень выше, что бы проверить асинхронность пихнул в setInterval с таймаутом 500ms, а вместо значения progress врубил Math.random() * 100.

Стало все окей. Прогресс бар стал дергаться в такт Math.random().

Сунул обратно, мало ли, меня проглючило - ничего.
Ну и как то так получилось, что в результате тестов я оставил this.progressObserver.next(this.progress); внутри обработчика события xhr.upload.onprogress, но setInterval не удалил, удалил только тело его коллбэка.

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


И все стало так как нужно, полоса загрузки стала обновляться, причем не абы как, а с интервалом setIterval.

Код получился вот такой:
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);
        });
    }


Соответственно, как только я получил такой результат - побежал сюда и стал строчить этот текст.

Почему так происходит?
Почему без setInterval Observable внутри onprogress не отдает корректно результаты?
Что вообще тут происходит?
  • Вопрос задан
  • 320 просмотров
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы