2015-08-20 176 views
1

我在循環的每次迭代中進行異步調用時都試圖使我的for循環同步行爲。循環內的異步函數調用

這裏是我的代碼:

pipeline: function(userContext, options, done){ 

    var orderData = []; 

    options.data.forEach(function(store, index){ 
     store.orders.forEach(function(order){ 
      shopify.getPipeline(userContext, {'order':order,'storeId':index}, function(result){ 
       var snapshotId = "30775bf1bb854c5d84c9c2af37bc8fb0"; 
       var resourceToQuery = config.structrUrls.getUrl("ConfigurationSnapshot") + '/' + snapshotId ; 
       var requestOptions = { 
        method: "GET", 
        timeout: 8000 
       }; 
       requestify.request(resourceToQuery, requestOptions) 
        .then(function(snapshotResult){ 
         result.snapshots = snapshotResult.getBody().result; 
         result.snapshots.configurationPayload = JSON.parse(snapshotResult.getBody().result.configurationPayload); 
         orderData.push(result); 
        }) 
        .catch(function(err){ 
         console.log (err); 
         done(err); 
        }); 
      }); 
     }); 
    }); 

    done(null, orderData); 

} 

我瞭解這裏的問題,但不知道如何解決它。讓我來解釋一下這個函數:

options.data包含一個商店數組,每個商店包含一個訂單數組。對於每一個訂單,我爲管道數據調用shopify.getPipeline()(這是一個同步操作),並且在回調函數中爲快照數據發出一個requestify請求(用於發出http請求的節點模塊),我希望在將其推入我的「orderData」數組之前追加到結果。當這一切完成後,我用我的訂單數據調用「完成」,一個回調函數。如您所見,由於requestify調用是異步的,因此在將任何數據添加到orderData數組之前調用done。

我想我需要使用某種承諾才能保證調用完成前的結果,但是我一直沒有成功實現對此函數的承諾。在q的文檔中,似乎我想要使用的函數是promise.all(),它返回一個承諾,該承諾由包含每個承諾的履行價值的數組實現,或者以相同的拒絕原因被拒絕作爲第一個被拒絕的承諾「。我無法看到如何將我的forEach循環轉換爲承諾數組。我也在看着async parallel function,並遇到了有關這組函數的相同問題。

任何幫助,非常感謝。謝謝!

回答

3

構建承諾使用數組中Promise.all,你可以map整個賣場的陣列,並再次跨越,訂單的陣列,返回承諾將爲其解決或者基於requestify.request結果否決每個訂單。合併產生的嵌套數組給你一個單一的承諾數組,然後可以傳遞給Promise.all

使用你的例子:

pipeline: function(userContext, options, done){ 
    var nestedPromises = options.data.map.forEach(function(store, index){ 
     return store.orders.map(function(order){ 
      return new Promise(function(resolve, reject){ 
       shopify.getPipeline(userContext, {'order':order,'storeId':index}, function(result){ 
        var snapshotId = "30775bf1bb854c5d84c9c2af37bc8fb0"; 
        var resourceToQuery = config.structrUrls.getUrl("ConfigurationSnapshot") + '/' + snapshotId ; 
        var requestOptions = { 
         method: "GET", 
         timeout: 8000 
        }; 
        requestify.request(resourceToQuery, requestOptions) 
         .then(function(snapshotResult){ 
          result.snapshots = snapshotResult.getBody().result; 
          result.snapshots.configurationPayload = JSON.parse(snapshotResult.getBody().result.configurationPayload); 
          resolve(result); 
         }) 
         .catch(function(err){ 
          reject(err); 
         }); 
       }); 
      }); 
     }); 
    }); 
    // Flatten nested array. 
    var promises = Array.prototype.concat.apply([], nestedPromises); 
    Promise.all(promises).then(function(orderData){ 
     done(null, orderData); 
    }).catch(function(err){ 
     done(err); 
    }); 
}