2017-11-19 5 views
0

GETルートを持つノード/エクスプレスサーバーがあります。このルートからクライアントに、インデックス付きオブジェクト配列で構成されたレスポンスを返す必要があります。各オブジェクトにはbase64エンコードイメージを取得する 'url'プロパティがありますbase64-imgというノード・ライブラリーを使用します。内部非同期コードを持つオブジェクトループのオブジェクトを反復するときに、変数を正しく追跡する方法はありますか?

オブジェクトのオブジェクトから始まり、各オブジェクトは、画像へのURLアドレスを持つ文字列であるプロパティ 'url'を持っています。 lodashでは、オブジェクトのオブジェクトをループしています。各ループの繰り返しは、現在の反復のobject.urlプロパティを受け取り、そのURLのターゲットイメージをbase64エンコーディングに変換するbase64Img.requestBase64を呼び出します。すべてのオブジェクトが繰り返し処理された後、オブジェクトのINDEXED配列(0,1,2など)の応答をクライアントに送信します。

ループが完了して非同期フローが原因ですべてのイメージが正しくエンコードされていることを確認する方法がわかりません。次のコードは機能しませんが、時々私は完全な配列を持つことがありますが、時にはそうではありませんが、クライアントは常にオブジェクトを含む配列を受け取って配列を返します。助けてください。

/* 

userProfileImages = { 
    {url: 'http://www.someurl.com/blah1'}, 
    {url: 'http://www.someurl.com/blah2'}, 
    {url: 'http://www.someurl.com/blah3'}, 
    {url: 'http://www.someurl.com/blah4'} 
} 

*/ 

let completeRequests = 0; 
let arrayOfUserProfileImages = []; 
_.map(userProfileImages, (userProfileImage, key) => { 

completeRequests++; 

let tmpCount = completeRequests; 
let tmpUserProfileImage = userProfileImage; 

// loop through each of the userProfileImages, 
// get each image by the url in userProfileImage 
base64Img.requestBase64(
    tmpUserProfileImage.url, 
    function(error, messageRes, body) { 

     // if image conversion successful, proceed 
     if (!error) { 

      // get the base64 code and set it as the new 
      // value of the userProfileImage url property 
      tmpUserProfileImage.url = body; 

      // push the object into the array 
      arrayOfUserProfileImages.push(tmpUserProfileImage); 
      console.log('ARRAY LENGTH:', arrayOfUserProfileImages.length); 
      console.log(arrayOfUserProfileImages); 

      // if number of request matches the total number 
      // of requests to complete, we are done, return 
      // the appropriate json response 
      if (tmpCount === numberOfRequestsToMake) { 
       console.log(arrayOfUserProfileImages); 
       return res.json({ userProfileImages: arrayOfUserProfileImages }); 
      } 

     // else return json error 
     } else { 
      return res.json({error: error}); 
     } 

    } // end callback 

); // end base64Img 

}); // end _.map 

答えて

1

ループ/アレイは、Promisesを使用すると非常に簡単です。

最初にrequestBase64コールバックをPromiseに変換します。コールバック関数の署名が(error, result)の場合は通常util.promisifyを使用できますが、この場合は署名の3つの引数に手動設定が必要です。

function requestBase64(url){ 
    return new Promise((resolve, reject) => { 
    base64Img.requestBase64(url, (error, messageRes, body) => { 
     if (error) return reject(error) 
     resolve(body) 
    }) 
    }) 
} 

は次に約束の配列を作成し、それぞれが、URLを要求し、応答を待ち、そしてURLとしてレスポンスボディを持つオブジェクトが作成されます。

let p = _.map(userProfileImages, async (userProfileImage, key) => { 
    let body = await requestBase64(userProfileImage.url) 
    let base64userProfileImage = _.cloneDeep(userProfileImage) 
    return _.merge(base64userProfileImage, { url: body }) 
}) 

次に、応答を送信する前に、アレイ内のすべての約束が解決するのを待ちます。

try { 
    let userProfileImages = await Promise.all(p) 
    return res.json({ userProfileImages: userProfileImages }) 
} catch (error){ 
    return res.json({ error: error }) 
} 

async/awaitそのrequirea Node.js 7.6+又はBabel.then()を使用しているプレーンなPromiseコードは大きく異なりません。

awaitを使用するには、async関数の内部にある必要があります。このコードをすべて格納している関数が何であれ、私はそれが高速ルートハンドラであると仮定し、asyncとタグ付けする必要もあります。

+0

ありがとう、これは私のすべての問題を解決しました。これらのasync/await/Promiseの概念を詳しく説明する、お勧めのリソースやオンラインクラス(udemy)はありますか?私は本当にこれをすべて知っていて、これを握っているのは難しい時です。ありがとうございました。 –

+0

申し訳ありません私は便利です。おそらく、非同期関数が最初にどのように働くのかを説明するものが必要なので、一般的な概念を得てからそれを約束に変換すれば、async/awaitは簡単なジャンプです。 – Matt

+0

ここには[それぞれの良い概要](https://blog.risingstack.com/asynchronous-javascript/)がありますが、イントロ/チュートリアルではあまりありません。 – Matt

関連する問題