【问题标题】:rxjs return result of event inside maprxjs返回地图内事件的结果
【发布时间】:2019-01-17 00:37:51
【问题描述】:

希望有人可以帮助我在下面的 http 请求的映射中返回 base64 字符串的 observable

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 = () =&gt; {

我想我需要将其转换为承诺并使用mergeMap?不知道怎么做。

更新

所以对此进行了另一次尝试.. 从 mergeMap 文档看起来这应该可以工作,调试我可以看到 blob 被传递给 reader.readAsDataURL(data);return reader.result; 永远不会触发,看起来我正在失去对 @ 的引用987654325@

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;
                }
            }));
    }

【问题讨论】:

  • fromEvent 没有被弃用(只有它是带有结果选择器的变体被弃用),是的,你有Observable&lt;Observable&lt;any&gt;&gt;
  • @martin 抱歉,我实际上并没有工作,知道我是如何做到这一点的吗?
  • 我不知道你想做什么
  • 你不必管道/映射 eventObservable 只需在最后返回它
  • @MehdiBenmoha 我需要映射,因为事件触发不提供任何响应。我现在已经想通了。最后我不得不使用一个主题,因为问题是 onloadend 事件在模板订阅 observable 之前触发,基本上是一种竞争条件。

标签: typescript rxjs rxjs6


【解决方案1】:

问题是 FileReader 的 onLoadEnd 事件是异步的,所以它在 map 函数中不起作用。

解决您的问题的一种方法是使用 Promise 包装您的函数,使用 from 从 Promise 创建一个 observable,然后使用 switchMap 运算符将您的 observable 映射到 Promise 中的新 observable。

现在,当您订阅生成的 observable 时,它​​将从 FileReader 发出结果。如果它拒绝,您可以使用 subscribe 方法的第二个参数获取错误。

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
)

【讨论】:

    【解决方案2】:

    好吧,最后想通了。所以我需要根据响应使用mergeMap,如果需要asBase64,可以从onloadend文件阅读器事件中创建一个新的observable。

    但由于这些行,它也不太有效(请参阅我原来问题中的代码)。

    let reader = new FileReader();
                        let eventObservable = fromEvent(reader, 'onloadend').pipe(map(() => {
                            return reader.result;
                        }));
                        reader.readAsDataURL(data);
                        return eventObservable;
    

    fromEvent 方法的问题是该事件只触发一次,在我的情况下是在我的 Angular 模板设法订阅 observable 之前触发的,解决方案是使用 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;
                    }
                }));
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-03-06
      • 1970-01-01
      • 2018-08-29
      • 1970-01-01
      • 2012-04-10
      • 1970-01-01
      • 1970-01-01
      • 2013-07-19
      相关资源
      最近更新 更多