繁体   English   中英

如何让 Observable Subject 返回同步数据

[英]How to make an Observable Subject return sync data

我正在使用 Angular 开发一个带有调整大小和预览功能的图像文件上传代码。 该项目有一个 HTML 文件输入,用于选择多个图像。 然后,在加载时,触发上传功能,调整大小和预览。 通过订阅调用服务上传和调整大小。 问题是当我选择要上传的多张图像时,处理调整大小的时间或其他原因会导致错误,因为订阅正在获取空数据(或延迟数据......)。

 onFileSelected(event: any) { // Reset progress bar this.progress = 0; this.waiting = true; const selectedFiles = <FileList>event.srcElement.files; // Resize images first this.resizeService.resizeImage(selectedFiles, this.maxWidth, this.maxHeight) .pipe( take(1) ) .subscribe( (data: any) => { // Add property name to obj Blob for (let i = 0; i < selectedFiles.length; i++) { data[i].name = selectedFiles[i].name; } this.resizedFiles = data; this.waiting = false; // Do upload this.onUpload(); // Reset input file this.fileInput.nativeElement.value = ''; }); }

调整大小服务:

 import { Injectable } from '@angular/core'; import { BehaviorSubject, Observable, Subject } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class resizeService { constructor() { } resizeImage(files: FileList, maxWidth: number, maxHeight: number): Observable<any> { let resizedFileSubject = new Subject(); let fileBlobArray: Blob[] = []; Array.from(files).map((file, i, { length }) => { let image: HTMLImageElement = new Image(); image.src = URL.createObjectURL(file); image.onload = () => { let width = image.width; let height = image.height; let canvas = document.createElement('canvas'); let ctx: any = canvas.getContext("2d"); let newHeight; let newWidth; const ratio = width / height; // Resize if needed if (width <= maxWidth && height <= maxHeight) { resizedFileSubject.next(file); } // Calculate aspect ratio if (width > height) { newWidth = maxHeight * ratio; newHeight = maxHeight; } else { newWidth = maxWidth * ratio; newHeight = maxWidth; } canvas.width = newWidth; canvas.height = newHeight; // Draw image on canvas ctx.drawImage(image, 0, 0, newWidth, newHeight); fileBlobArray.push(this.b64ToBlob(canvas.toDataURL("image/jpeg"))); // console.log('push: ', fileBlobArray) // Detect end of loop if (i + 1 === length) { // Wait to get async data - Workaround :( // setTimeout(() => { resizedFileSubject.next(fileBlobArray); // console.log('next: ', fileBlobArray) // }, 1000); } } }); return resizedFileSubject.asObservable(); } /** * Convert BASE64 to BLOB * @param base64Image Pass Base64 image data to convert into the BLOB */ private b64ToBlob(base64Image: string) { const parts = base64Image.split(';base64,'); const imageType = parts[0].split(':')[1]; const decodedData = window.atob(parts[1]); const uInt8Array = new Uint8Array(decodedData.length); for (let i = 0; i < decodedData.length; ++i) { uInt8Array[i] = decodedData.charCodeAt(i); } return new Blob([uInt8Array], { type: imageType }); } }

我必须做的是一种解决方法,即添加 1 秒的 setTimeout 以“等待”直到一切完成(同步异步调用??)。

错误发生在这里:

for (let i = 0; i < selectedFiles.length; i++) {
  data[i].name = selectedFiles[i].name;
}

错误:

ERROR TypeError: Cannot set properties of undefined (setting 'name')
    at SafeSubscriber._next (app.component.ts:55)
    at SafeSubscriber.__tryOrUnsub (Subscriber.js:183)
    at SafeSubscriber.next (Subscriber.js:122)
    at Subscriber._next (Subscriber.js:72)
    at Subscriber.next (Subscriber.js:49)
    at TakeSubscriber._next (take.js:35)
    at TakeSubscriber.next (Subscriber.js:49)
    at Subject.next (Subject.js:39)
    at Image.image.onload [as __zone_symbol__ON_PROPERTYload] (resize.service.ts:56)
    at Image.wrapFn (zone.js:763)

任何帮助表示赞赏。

请注意,您将selectedFiles (一个列表)传递给了resizeImage()函数。 您假设您将在订阅中获得调整大小的图像列表(与selectedFiles具有相同的大小)。 但你只是next()这一行中的一个文件:

 if (width <= maxWidth && height <= maxHeight) {
          resizedFileSubject.next(file);
 }

这就是为什么您在此处收到data[i].name部分错误的原因:

   // Add property name to obj Blob
    for (let i = 0; i < selectedFiles.length; i++) {
      data[i].name = selectedFiles[i].name;
    }

我建议在单独的数组中推送调整大小或未调整大小的图像,并在调整大小操作结束时使用next()整个数组。

暂无
暂无

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

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