簡體   English   中英

如何在redux-observable中正確使用forkJoin?

[英]How to use forkJoin correctly in redux-observable?

我正在使用redux-observable。

所有附件分別上傳后,我正在嘗試發送郵件。

此發送郵件API的過程是

  1. 將郵件內容添加到草稿中
  2. 將附件分別添加到草稿中
  3. 上傳所有附件后,從草稿發送郵件

現在,下面的代碼可以成功地分別上傳所有附件。 但是,我不知道如何等待它們完成。

學習forkJoin 此文檔后 ,我認為我需要使用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$ ,請檢查如何在redux-observable中處理異步函數?

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM