web-dev-qa-db-ja.com

各プロミスに対してthen()でaxios.allを使用することは可能ですか?

イベントをトリガーしてデータを取得するReactコンポーネントがあります。これにより、データを取得するための動的な数のストアドプロシージャ呼び出しが発生し、各呼び出しのデータはまったく異なる場所に格納されます。それから、すべてのデータが受信されて利用可能になったら、再レンダリングする必要があります。

Axios呼び出しの数は動的であるため、次のように配列を作成してaxios.allに挿入しています。

let promises = [];

for (let i = 0; i < requests.length; i++) {
    promises.Push(axios.get(request[i].url, { params: {...} }));
}

axios.all(promises).then(/* use the data */);

問題は、各axiosリクエストがまったく異なる場所のオブジェクトに追加されるデータを返すことです。単一のthenの正しい場所にそれらをすべて配置する方法がないので(どの応答がどの場所に行くのかをどのように知ることができますか?)、私はこのようなことを試みました:

let promises = [];

for (let i = 0; i < requests.length; i++) {
    promises.Push(
        axios.get(request[i].url, { params: {...} })
            .then(response => {myObject[request[i].saveLocation] = response.data;})
    );
}

axios.all(promises).then(/* use the data */);

しかし、これは期待どおりには機能しません。各thenの後のgetが実行されますが、axios.allに接続されたthenの十分後までは実行されません。私のコードはデータをオブジェクトに保存する前に使用しようとするため、これは明らかに問題です。

対応するプロミスが解決された後に実行される各axios.getに対して個別のthen呼び出しを行い、その後にのみ実行される最後のthenを呼び出す方法はありますかallが解決され、オブジェクトにデータが入力されたのでデータを使用しますか?

12
nanoguy

さて、各thengetを使用せずに必要なことを行う方法を見つけました。 axios.getに渡されたパラメーターには保存場所を決定するのに十分な情報が含まれているため、応答からパラメーターを読み取ることができるため、次のようなことができます。

let promises = [];

for (let i = 0; i < requests.length; i++) {
    promises.Push(axios.get(request[i].url, { params: {...} }));
}

axios.all(promises)
    .then(axios.spread((...args) => {
        for (let i = 0; i < args.length; i++) {
            myObject[args[i].config.params.saveLocation] = args[i].data;
        }
    }))
    .then(/* use the data */);

これにより、使用前にすべてのデータが受信され、オブジェクトに保存されます。

26
nanoguy

2回目の試行の動作が実際にそのようなものである場合、それはaxiosがPromise/A +に準拠していないことを示しています。 thenコールバックの戻り値は、そのthenによって返されるpromiseが満たされる値でなければなりません。これは配列にプッシュする約束なので、axios.allがその約束に対して返す値は、最初にthenコールバックを実行することによってのみ知ることができます。

イベントはthenコールバックで明示的に値を返しませんが、これは上記のルールに影響しません。その場合、戻り値はundefinedであり、that対応するプロミスが解決されると、axios.allによって提供される値。

特にルール2.2.7、2.2.7.1、2.3.2.1、2.3.2.2を参照してください Promise/A +の仕様で )。

したがって、代わりにPromise/A +準拠のpromise実装を使用することをお勧めします。 request-promise など、他にもいくつかのライブラリがあります。

または、ネイティブのES6 Promise実装を使用して、 http.requestメソッドを指定 を使用することもできます。

ES6はPromise.allを提供し、約束が提供されたのと同じ順序で解決された値を提供することを保証します。

2
trincot

それぞれのthen関数でアタッチされた配列にプロミスを渡すと、初期コードは意図したとおりに正常に機能します。

let promises = []; // array to hold all requests promises with their then
for (let i = 0; i < requests.length; i++) {
    // adding every request to the array
    promises.Push(
        axios.get(request[i].url, { params: { ...} })
            .then(response => { myObject[request[i].saveLocation] = response.data; })
    );
}
// Resolving requests with their callbacks before procedding to the last then callback
axios.all(promises).then(/* use the data */);
0
mohamed hussein