2015-08-20 2 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() для данных конвейера (это синхронная операция), а в обратном вызове я делаю запрос запроса (модуль узла, используемый для создания http-запросов) для данных моментальных снимков, которые я хочу добавьте результат, прежде чем нажимать его на мой массив orderData. Когда все это завершается, я вызываю «done», функцию обратного вызова, с моей orderData. Как вы можете видеть, поскольку запрос вызовов является асинхронным, выполняется вызов до того, как любые данные будут добавлены в массив orderData.

Я думаю, что мне нужно использовать какое-то обещание, чтобы гарантировать результат, прежде чем позвонить, но я не смог выполнить обещание в эту функцию. В документации для q кажется, что функция, которую я хотел бы использовать, - это обещание. All(), которое «возвращает обещание, которое выполняется с массивом, содержащим значение выполнения каждого обещания, или отклоняется с той же причиной отказа как первое обещание быть отвергнутым ». Я не понимаю, как перевести мой цикл forEach в массив обещаний. Я также смотрел на async parallel function и столкнулся с той же проблемой в отношении множества функций.

Любая помощь очень ценится. Благодаря!

ответ

3

Чтобы построить массив Promises для использования в 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); 
    }); 
} 
Смежные вопросы