希望有人可以帮助我,有一个可观察到的对象,它在下面的http请求的映射内返回base64字符串
transform(url: string, asBase64: boolean): Observable<any> {
return this.http
.get(url, {responseType: 'blob'})
.pipe(map(val => {
if (!asBase64) {
return this.sanitizer.bypassSecurityTrustUrl(URL.createObjectURL(val))
}
let base64Data = null;
let reader = new FileReader();
reader.readAsDataURL(val);
reader.onloadend = () => {
base64Data = reader.result; // need to return this!
console.log(base64Data);
};
}));
}
问题是我需要有条件地返回结果reader.onloadend = () => {
我想我需要将其转换为Promise并使用mergeMap吗?不确定如何。
更新
因此还有另外一个问题。.从mergeMap文档看来这应该可以工作,调试时我可以看到将blob传递给reader.readAsDataURL(data);
,但是return reader.result;
从未触发,看起来我正在丢失对reader
transform(url: string, asBase64: boolean): Observable<any> {
return this.http
.get(url, {responseType: 'blob'})
.pipe(map(val =>
<any>(asBase64 ? val : this.sanitizer.bypassSecurityTrustUrl(URL.createObjectURL(val)))
)).pipe(mergeMap(data => {
if (!asBase64) {
return of(data)
} else {
let reader = new FileReader();
let eventObservable = fromEvent(reader, 'onloadend').pipe(map(() => {
return reader.result;
}));
reader.readAsDataURL(data);
return eventObservable;
}
}));
}
答案 0 :(得分:1)
问题在于FileReader onLoadEnd事件是异步的,因此它在map函数内部不起作用。
解决问题的一种方法是用Promise包装函数,用from从诺言中创建一个可观察对象,然后使用switchMap运算符将您的可观察对象映射到新的可观察对象。答应。
现在,当您预订结果的可观察对象时,它将从FileReader发出结果。如果拒绝,则可以使用subscription方法的第二个参数获取错误。
import {from} from 'rxjs'
import {switchMap} from 'rxjs/operators'
transform(url: string, asBase64: boolean): Observable<any> {
return this.http
.get(url, {responseType: 'blob'})
.pipe(
switchMap(
val => from( // create the observable from a promise
new Promise((resolve, reject) => { //create a new Promise
if (!asBase64) {
resolve(this.sanitizer.bypassSecurityTrustUrl(URL.createObjectURL(val))) //resolve if base64
}
const reader = new FileReader();
reader.readAsDataURL(val);
reader.onloadend = () => resolve(reader.result); //resolve when it finishes to load the file
reader.onerror = () => reject(reader.error); //rejects if there was an error while reading the file
})
)
)
);
}
...
const file$ = transform(url, asBase64)
file$.subscribe(
(file) => console.log(file), // do stuff with the file here
(error) => console.log(error) // there was an error while reading the file
)
答案 1 :(得分:0)
Ok最终想到了这一点。因此,我需要根据响应使用mergeMap
,并根据需要使用asBase64
从onloadend
文件读取器事件中创建一个新的可观察对象。
但是由于这些行,它也不起作用(请参阅我最初问题中的代码)。
let reader = new FileReader();
let eventObservable = fromEvent(reader, 'onloadend').pipe(map(() => {
return reader.result;
}));
reader.readAsDataURL(data);
return eventObservable;
fromEvent方法的问题在于,该事件仅触发一次,而在我的情况下,是在我的Angular模板成功订阅可观察对象之前触发的,所以解决方案是使用Subject
不确定是否理想在这种情况下,但对我来说似乎还可以。
transform(url: string, asBase64: boolean): Observable<any> {
return this.http
.get(url, {responseType: 'blob'})
.pipe(map(val =>
<any>(asBase64 ? val : this.sanitizer.bypassSecurityTrustUrl(URL.createObjectURL(val)))
)).pipe(mergeMap(data => {
if (!asBase64) {
return of(data)
} else {
let reader = new FileReader();
let subject = new Subject<any>();
reader.onloadend = () => {
subject.next(reader.result);
};
reader.readAsDataURL(data);
return subject;
}
}));
}