Javascript 如何在redux observable中正确使用forkJoin?

Javascript 如何在redux observable中正确使用forkJoin?,javascript,redux,rxjs,rxjs5,redux-observable,Javascript,Redux,Rxjs,Rxjs5,Redux Observable,我正在使用redux observable 我试图在所有附件分别上传后发送邮件 此发送邮件API的过程是 将邮件内容添加到草稿中 在草稿中单独添加附件 上传所有附件后,从草稿发送邮件 现在,下面的代码可以分别成功上载所有附件。然而,我不知道如何等待它们全部完成 学习之后,我认为我需要使用forkJoin,但是我没有弄清楚在这种情况下如何正确使用它 export const addMailContentSucceedEpic = (action$, store) => action$

我正在使用redux observable

我试图在所有附件分别上传后发送邮件

此发送邮件API的过程是

  • 将邮件内容添加到草稿中
  • 在草稿中单独添加附件
  • 上传所有附件后,从草稿发送邮件
  • 现在,下面的代码可以分别成功上载所有附件。然而,我不知道如何等待它们全部完成

    学习之后,我认为我需要使用
    forkJoin
    ,但是我没有弄清楚在这种情况下如何正确使用它

    export const addMailContentSucceedEpic = (action$, store) =>
      action$
        .ofType(ADD_MAIL_CONTENT_SUCCEED)
        .expand(action => {     // expand here helps upload all attachments separately
          const restAttachments = removeFirstAttachment(action.payload.attachments);
    
          if (isEmpty(restAttachments)) return Observable.empty();
    
          return Observable.of({
            ...action,
            payload: {
              ...action.payload,
              attachments: restAttachments
            }
          });
        })
        .map(action => addAttachment({ mailId: action.payload.mailId, attachment: first(action.payload.attachments) }));
    
    export const addAttachmentEpic = (action$, store) =>
      action$
        .ofType(ADD_ATTACHMENT)
        .mergeMap(action => getBase64FromFile(action))
        .mergeMap(action =>
          ajax
            .patch(url, { base64: action.payload.base64 })
            .map(() => addAttachmentSucceed({ mailId: action.payload.mailId }))
            .catch(addAttachmentFailed)
        );
    
    export const addAttachmentSucceedEpic = (action$, store) =>
      action$
        .ofType(ADD_ATTACHMENT_SUCCEED)
        // Here is wrong, I need wait all attachments be uploaded
        // I tried to add a global `let = tasks$[];` on the top, but I am not clear where and how I can push each task (add attachment) to it
        // Then add .mergeMap(action => Observable.forkJoin(tasks$)) here, but it probably wrong to be added after .ofType(ADD_ATTACHMENT_SUCCEED)
        // In my mind, it needs to be after something `ADD_ALL_ATTACHMENTS_SUCCEED`
        .map(action => sendMailFromDraft({ mailId: action.payload.mailId }));
    
    更新

    我将尝试更改为下面的结构

    也许我可以将
    addAttachments$
    作为有效负载(?)传递,或者将其创建为全局变量。稍后我会提供更多更新

    const addAttachments$ = [
      ajax.patch(url, { base64: getBase64(first(action.payload.attachments) })),
      ajax.patch(url, { base64: getBase64(second(action.payload.attachments) })),
      ajax.patch(url, { base64: getBase64(third(action.payload.attachments) })),
      // ...
    ];
    
    export const addMailContentSucceedEpic = (action$, store) =>
      action$
        .ofType(ADD_MAIL_CONTENT_SUCCEED)
        .mergeMap(action =>
          Observable.forkJoin(addAttachments$)
          .map(() => sendMailFromDraft({ mailId: action.payload.mailId }))
        )
        .catch(/* ... */);
    

    这是我最后的解决办法

    因为读取文件也是异步的,所以在这个解决方案中有两个
    forkJoin

    一个
    forkJoin
    用于等待读取所有文件。另一个
    forkJoin
    用于等待上传所有附件

    对于代码中的
    getBase64FromFile$
    ,请检查

    export const addMailContentSucceedEpic=(action$,store)=>
    行动$
    .of类型(添加邮件内容成功)
    .mergeMap(操作=>addTasks$(操作))
    .mergeMap(action=>Observable.forkJoin(action.payload.posts$)
    .map(()=>sendMailFromDraft({mail:action.payload.mail}))
    );
    函数getPosts(base64Array,action){
    让帖子$=[];
    for(设i=0;igetPosts(base64Array,action));
    }
    
    代码中有
    forkJoin
    的地方在哪里?@martin刚刚添加了更多!感谢您回来并添加解决方案!非常有助于子孙后代。@Jayphapps不,你对我们的帮助超出了我们的能力,谢谢!
    export const addMailContentSucceedEpic = (action$, store) =>
      action$
        .ofType(ADD_MAIL_CONTENT_SUCCEED)
        .mergeMap(action => addTasks$(action))
        .mergeMap(action => Observable.forkJoin(action.payload.posts$)
          .map(() => sendMailFromDraft({ mail: action.payload.mail }))
        );
    
    
    function getPosts(base64Array, action) {
      let posts$ = [];
    
      for (let i = 0; i < base64Array.length; ++i) {
        posts$ = [...posts$, ajax.patch(url, { base64: base64Array[i] })];
      }
    
      return {
        ...action,
        payload: {
          ...action.payload,
          posts$
        }
      };
    }
    
    function addTasks$(action) {
      let readFiles$ = [];
    
      for (let i = 0, attachmentIds = Object.keys(action.payload.attachments); i < attachmentIds.length; ++i) {
        const attachmentId = attachmentIds[i];
        const attachment = action.payload.attachments[attachmentId];
    
        readFiles$ = [...readFiles$, getBase64FromFile$(attachment)];
      }
    
      return Observable.forkJoin(readFiles$)
        .map(base64Array => getPosts(base64Array, action));
    }