3

今日、興味深い問題に遭遇しました。ファイルのアップロードがあるアプリに取り組んでおり、進行状況バーを実装したいと考えています。アプリは React/Redux/Redux-Observable を使用して作成されています。アップロードの進行状況に対してアクションをディスパッチしたい。これを実装するために私がしたことは次のとおりです。

withProgress(method, url, body = {}, headers = {}) {
    const progressSubscriber = Subscriber.create();

    return {
        Subscriber: progressSubscriber,
        Request:    this.ajax({ url, method, body, headers, progressSubscriber }),
    };
}

すべての ajax リクエストを行うために使用するクラスがあります。渡されたパラメーターを使用してthis.ajax呼び出します。Observable.ajax

export const blobStorageUploadEpic = (action$) => {
    return action$.ofType(a.BLOB_STORAGE_UPLOAD)
    .mergeMap(({ payload }) => {
        const { url, valetKey, blobId, blobData, contentType } = payload;

        const { Subscriber, Request } = RxAjax.withProgress('PUT', `${url}?${valetKey}`, blobData, {
            'x-ms-blob-type': 'BlockBlob',
            'Content-Type':   contentType,
        });

        const requestObservable = Request
        .map(() => ({ type: a.BLOB_STORAGE_UPLOAD_SUCCESS, payload: { blobId } }))
        .catch((err) => Observable.of({ type: a.BLOB_STORAGE_UPLOAD_FAILURE, err }));

        return Observable.fromSubscriber(Subscriber)
        .map((e) => ({ percentage: (e.loaded / e.total) * 100 }))
        .map((percentage) => ({ type: a.BLOB_STORAGE_UPLOAD_PROGRESS, payload: { percentage} }))
        .merge(requestObservable);
    });
};

これは私の叙事詩です。サブスクライバーを取得し、サブスクライバーを取得するためのカスタム静的メソッドを作成Observableしました。Request次に、それを(である)とマージしObservableます。

Observable.fromSubscriber = function fromSubscriber(externalSubscriber) {
    return Observable.create((subscriber) => {
        externalSubscriber.next =     (val) => subscriber.next(val);
        externalSubscriber.error =    (err) => subscriber.error(err);
        externalSubscriber.complete = () => subscriber.complete();
    });
};

最後に、私が書いたカスタム静的メソッドを次に示しますObservable。これを書いた理由は 2 つあります。1. 同様の問題を扱っている他の誰かの例として (私は自分で書く前にObservablea から aを作成する方法を見つけようと多くの時間を費やしましたSubscriber) 2. これがこの目標を達成するための最良の方法であるかどうかを尋ねるため. rxjsこれを行う既存の方法があると思いますが、それを見つけることができませんでした。

4

1 に答える 1

7

それは基本的に a のSubject目的であり、次のようにも機能するはずです。

export const blobStorageUploadEpic = (action$) => {
    return action$.ofType(a.BLOB_STORAGE_UPLOAD)
    .mergeMap(({ payload }) => {
        const { url, valetKey, blobId, blobData, contentType } = payload;

        const progressSubscriber = new Rx.Subject();
        const request = Rx.Observable.ajax({
            method: 'PUT',
            url: `${url}?${valetKey}`,
            body: blobData,
            headers: {
                'x-ms-blob-type': 'BlockBlob',
                'Content-Type':   contentType,
            },
            progressSubscriber
        });

        const requestObservable = request
            .map(() => ({ type: a.BLOB_STORAGE_UPLOAD_SUCCESS, payload: { blobId } }))
            .catch((err) => Observable.of({ type: a.BLOB_STORAGE_UPLOAD_FAILURE, err }));

        return progressSubscriber
            .map((e) => ({ percentage: (e.loaded / e.total) * 100 }))
            .map((percentage) => ({ type: a.BLOB_STORAGE_UPLOAD_PROGRESS, payload: { percentage} }))
            .merge(requestObservable);
    });
};

より一般的な例を次に示します (ライブ@jsfiddle ):

let data = "";
for (let c = 0; c < 100000; ++c) {
    data += "" + Math.random();
}

const progressSubscriber = new Rx.Subject();
const request = Rx.Observable.ajax({
  method: 'POST',
  url: "/echo/json/",
  body: JSON.stringify({ data }),
  progressSubscriber
});

progressSubscriber
  .merge(request)
  .subscribe(console.log);
于 2017-01-26T23:27:42.107 に答える