如何在redux-observable中处理异步函数?

时间:2017-11-27 03:46:00

标签: javascript redux rxjs rxjs5 redux-observable

我正在使用RxJS和redux-observable。

我试图在史诗中读取文件。在我的情况下,我必须在史诗中这样做,因为其他一些史诗会被export const uploadAttachmentEpic = (action$, store) => action$ .ofType(UPLOAD_ATTACHMENT) .map(action => { const reader = new FileReader(); reader.onload = () => { return { ...action, payload: { ...action.payload, base64: reader.result } } }; reader.readAsDataURL(action.payload.file); }) .mergeMap(action => ajax .post( /* use action.payload.base64 */ ) .map(uploadAttachmentSucceed) .catch(uploadAttachmentFailed) ); 操作员触发这个史诗般的多次“未知”时间。

但是由于FileReader是异步的,下面的代码不起作用。

特别是RxJS处理这个问题的方法是什么?感谢

{{1}}

2 个答案:

答案 0 :(得分:3)

范的回答(截至撰写本文时)很好,但有一些重要的注意事项:

  • 它立即开始读取文件而不是懒惰。因此,只要在任何人订阅之前调用readFile(file)即可启动它。这很容易出错,因为某人可能不会立即同步订阅它,然后reader.onload会错过它。 Observable是理想的完全懒惰和可重复的工厂。

  • 它从不在观察者上调用obs.complete(),因此订阅可能是内存泄漏,因为它永远不会结束。

  • 观察者的方法没有绑定,因此reader.onerror = obs.error实际上不起作用。相反,您需要e => obs.error(e)obs.error.bind(obs) See here for reference on why

  • 不会取消取消订阅的阅读。

我将如何做到这一点:

function readFile(file){
  // Could use Observable.create (same thing) but I
  // prefer this one because Observable.create is
  // not part of the TC39 proposal
  return new Observable(observer => {
    const reader = new FileReader();
    reader.onload = (e) => {
      observer.next(reader.result);
      // It's important to complete() otherwise this
      // subscription might get leaked because it
      // "never ends"
      observer.complete();
    };
    reader.onerror = e => observer.error(e);
    reader.readAsDataURL(file);

    // unsubscribe handler aka cleanup
    return () => {
      // LOADING state.
      // Calling abort() any other time
      // will throw an exception.
      if (reader.readyState === 1) {
        reader.abort();
      }
    };
  });
}

这种模式几乎可以应用于任何API,因此了解其工作原理非常方便。

我希望范不介意批评!我不是故意冒犯,只是想分享知识。

答案 1 :(得分:1)

您的文件读取过程确实返回Observable。异步过程没有正确处理。我建议创建一个文件读取函数,它首先返回一个observable。然后将它附加到flapMap()

  function readFile(file){
    let reader = new FileReader();
      return Observable.create(obs => {
        reader.onload = function (e) {
            obs.next(reader.result);
        };
        reader.onerror = obs.error;
    })
        reader.readAsDataURL(file);
   }

然后在你的代码中你可以像..flatMap(file => readFile(file))那样合并它。

相关问题