简体   繁体   English

如何在redux-observable中处理异步功能?

[英]How to handle async function in redux-observable?

I am using RxJS and redux-observable. 我正在使用RxJS和redux-observable。

I am trying to read file in epic. 我正在尝试读取史诗级的文件。 In my case, I have to do it in epic, because some other epic trigger this epic multiple "unknown" times by expand operator. 就我而言,我必须在史诗中执行此操作,因为其他一些史诗会由expand运算符多次触发该史诗。

But since FileReader is async, the code below does not work. 但是由于FileReader是异步的,因此下面的代码不起作用。

What is the correct way especially RxJS way to handle this? 特别是RxJS处理此问题的正确方法是什么? Thanks 谢谢

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

Fan's answer (as of this writing) is good but has some caveats to it that are important: 范的答案(截至撰写本文时)是好的,但有一些重要的警告事项:

  • It starts reading the file immediately instead of lazily. 它立即开始读取文件,而不是懒惰地读取文件。 So just calling readFile(file) starts it even before anyone has subscribed. 因此,即使在没有任何人订阅之前,只需调用readFile(file)启动它。 This is error-prone because it's possible that someone might not synchronously subscribe to it right away and then the reader.onload will miss it. 这很容易出错,因为有人可能没有立即同步订阅它,然后reader.onload会错过它。 Observables are ideally made completely lazy and repeatable factories. 理想情况下,可观察对象是完全懒惰且可重复的工厂。

  • It never calls obs.complete() on the observer, so it's possible the subscription will be a memory leak because it never ends. 它永远不会在观察者上调用obs.complete() ,因此预订可能会因为obs.complete()而导致内存泄漏。

  • The methods on the observer are not bound, so reader.onerror = obs.error won't actually work. 观察者上的方法reader.onerror = obs.error ,因此reader.onerror = obs.error实际上不会起作用。 Instead you need to either e => obs.error(e) or obs.error.bind(obs) See here for reference on why 相反,您需要e => obs.error(e)obs.error.bind(obs) 请参阅此处以获取有关为什么的参考

  • It doesn't abort the reading on unsubscribe. 它不会终止退订时的读取。

Here's how I would do it: 这是我的处理方式:

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

This pattern can be applied to nearly any API, so it's pretty handy to understand exactly how it works. 这种模式几乎可以应用于任何API,因此很容易了解确切的工作方式。


I hope Fan doesn't mind the critique! 我希望范不介意批评! I don't mean to offend, just want to share knowledge. 我并不是要冒犯,只是想分享知识。

Your file reading process does return an Observable. 您的文件读取过程确实返回了一个Observable。 The async process is not handeled properly. 异步过程未正确处理。 I suggest to create an file reading function which return an observable first. 我建议创建一个文件读取函数,该函数首先返回一个可观察的对象。 then attach it to flapMap() 然后将其附加到flipMap()

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

then in your code you can merge it in like ..flatMap(file=>readFile(file)) 然后可以在您的代码中将其合并为..flatMap(file => readFile(file))

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

相关问题 如何处理每个字段的异步更新onUpdate并使用redux-form和redux-observable保持ID - How to handle async update onUpdate of each field and keep ids using redux-form and redux-observable 在可以通过redux-observable完成一些异步操作之后,如何对redux操作进行排序? - How can I sequence redux actions after some async action completed in redux-observable? 如何在redux-observable中正确使用forkJoin? - How to use forkJoin correctly in redux-observable? 如何在 redux-observable 上进行 PUT 和 DELETE - How to make PUT and DELETE on redux-observable 如何正确使用redux-observable并承诺? - How to use redux-observable and promise correctly? 如何在 redux-observable 史诗中链接 RxJS observable? - How can I chain RxJS observable in a redux-observable epic? 如何使用 redux-observable 在 POST、PUT、DELETE 成功后执行回调 function - How to execute call back function after POST, PUT, DELETE success by using redux-observable 我如何在史诗中使用“ const”? Redux可观察到的ES6箭头功能 - How can I use “const” in epic? Redux-observable ES6 arrow function 如何在redux-observable中执行史诗中的副作用? - How to perform side-effect inside of an epic in redux-observable? 如何从redux-observable调度多个动作? - How to dispatch multiple actions from redux-observable?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM