2016-02-28 1 views
0

У меня есть функция, которая выполняет несколько асинхронных вызовов, которые заполняют один и тот же объект возвращаемыми данными. Мне нужно что-то сделать с данными, когда объект полностью заполнен, и поскольку есть несколько вызовов, это не основной сценарий обратного вызова/обещания.Как использовать обещание, когда переменная заполняется из цикла for

Возможно ли создать обещание в таком случае? Упрощенный код:

price_options = [] // when this is populated from all the async calls, I need to do stuff with it 
sheet_columns = [3,5,7,89] 

useServiceAccountAuth(credentials, function(error){ //google docs api 

    for (var i = 0; i < sheet_columns.length; i++) { 
    var params = {column_number: sheet_cols[i]} 

    do_async_call(params, function (e, data) { 
     data.forEach(function(item) { 
     price_options.push(item) 
     }) 
    }) 
    } 
}) 
+1

Использование 'Promise.all' – Bergi

+0

которые обещают библиотеку вы используете? – Darshan

+0

@ Bergi Можете ли вы уточнить? Я использую Q, только потому, что у меня есть некоторый опыт работы с ним. – ilyo

ответ

1

В других ответах имеется так много дезинформации.

Что вам нужно сделать, это использовать Promise.all() для объединения всех обещаний. Promise.all() берет массив обещаний и возвращает одно обещание, которое разрешает, когда все обещания в массиве были разрешены.

Итак, теперь вам нужно создать функцию, которая принимает каждую запись params, и создает для нее Promise для данных и вставляет ее в новый массив.

Так как мы используем Обещания, давайте избавимся от всех других обратных вызовов у вас есть в вашем коде:

// The "functionNameAsync" convention indicates that the function returns Promises. 
// This convention was coined by Bluebird's promisifying functions. 

// Takes credentials 
// Returns a promise that rejects on error, or resolves with nothing on no error. 
const useServiceAccountAuthAsync = credentials => 
    new Promise((resolve, reject) => 
    useServiceAccountAuth(credentials, err => err ? reject(err) : resolve())); 

const doCallAsync = params => 
    new Promise((resolve, reject) => 
    do_async_call(params, (err, data) => err ? reject(err) : resolve(data))); 

/* If you opt to use Bluebird, everything above this line can be replaced with: 
const useServiceAccountAuthAsync = Promise.promisify(useServiceAcountAuth); 
const doCallAsync = Promise.promisify(do_async_call); 

it would even be faster than my version above. */ 

// Now time for the actual data flow: 

const sheet_columns = [3,5,7,89] 

useServiceAccountAsync() 
    .then(() => { 
    const arrayOfAsyncCallPromises = sheet_columns 
    .map(columnNumber => ({column_number: sheet_cols[columnNumber]})) 
    .map(doCallAsync); 
    //.map(param => doCallAsync(param)) equivalent to above 

    return Promise.all(arrayOfAsyncCallPromises); 
    }) 
    .then(price_options => { 
    // use here 
    }) 
    .catch(err => { 
    // handle errors here 
    }); 
-1

Как и другие ребята заявили использование Promise.all, я написал этот фрагмент для вас с Promise.all, посмотрим.

price_options = []; 
sheet_columns = [3,5,7,89]; 
var promises = []; 

useServiceAccountAuth(credentials, function(error){ //google docs api 

    for (var i = 0; i < sheet_columns.length; i++) { 
    var params = {column_number: sheet_cols[i]} 

    // create a new promise and push it to promises array 
    promises.push(new Promise(function(resolve, reject) { 
    do_async_call(params, function (e, data) { 
     resolve(data); 
    }); 
    })); 
    } 

    // now use Promise.all 
    Promise.all(promises).then(function (args) { 
    args.forEach(function (data, i) { 
     data.forEach(function(item) { 
     price_options.push(item) 
     }); 
    }); 
    // here do your stuff which you want to do with price_options 
    }); 
}) 
+0

В вашем коде есть синтаксические ошибки. –

+0

Исправленные ошибки –

0

Вы можете сделать это:

let results = sheet_columns.map(c => ({column_number: c})) 
    .map(params => new Promise((resolve, reject) => { 

    do_async_call(params, (e, data) => { 
     if(e) { 
      reject(e); 
     } else { 
      resolve(data); 
     } 
    }) 
})) 

Promise.all(results).then(arr => Array.prototype.concat.apply([], arr)).then(price_options => doSomething(price_options)) 

Working jsbin here

-1

Если вы хотите использовать обещание, обернуть функцию do_async_call в функции, возвращающей обещание.

price_options = []; 
sheet_columns = [3,5,7,89] 

useServiceAccountAuth(credentials, function(error){ //google docs api 

    var promise_array = []; 
    for (var i = 0; i < sheet_columns.length; i++){ 
     var params = {column_number: sheet_cols[i]} 
     var promise = do_async_promise(params); 
     promise_array.push(promise); 
    } 
    Q.all(promise_array).then(function(){ 

    //do your operation with price_options here; 
    }); 

}) 

function do_async_promise(params){ 
    var deferred = Q.defer(); 
    do_async_call(params, function (e, data) { 
     data.forEach(function(item) { 
     price_options.push(item); 
     }); 
     deferred.resolve(); 
    }) 
    return deferred.promise; 
} 

 Смежные вопросы

  • Нет связанных вопросов^_^