簡體   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