2016-05-20 7 views
0

Я немного борюсь за обработку асинхронных вызовов по запросам, как я могу получить ответ в правильном порядке.Обработка асинхронных вызовов по запросам в node.js

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

var jsonObj = {}; 
var jsonArray = []; 
for (var i = 0; i < userArray.length; i++) { 
    var userJSON = userArray[i]; 
    if (typeof userJSONJSON.list_of_emails != 'undefined') { 
     conn.query('insert into user_tble set ?', userJSON, function (err, ins) { 
      conn.query('insert into user_emails (user_id,email_address,) values ?', [globalEmailAddressArray], function (err, ins2) { 
       conn.query('insert into user_phones (user_id,phone_number) values ?', [globalPhoneNumberArray], function (err, ins3) { 
        conn.query('insert into user_pictures (user_id,pic_url) values ?', ['http://localhost:300/somepicture'], function (err, ins4) { 
         jsonObj["result"] = "executed1"; 
         jsonArray.push(jsonObj); 
         res.status(200).json(arr: jsonArray) 
        }) 
       }) 
      }) 
     }); 
    } else if (typeof userJSONJSON.list_of_phones != 'undefined') { 
     conn.query('insert into user_phones (user_id,phone_number) values ?', [globalPhoneNumberArray], function (err, ins3) { 
        conn.query('insert into user_pictures (user_id,pic_url) values ?', ['http://localhost:300/somepicture'], function (err, ins4) { 
         jsonObj["result"] = "executed2"; 
         jsonArray.push(jsonObj); 
         res.status(200).json(arr: jsonArray) 
        }) 
       }) 
    } 
} 

если я дать полезную нагрузку что-то вроде

{ 
    "pay_load":[ 
     { 
      "list_of_emails": [ 
       {"email":"[email protected]"} 
       ], 
      "last_name": "", 
      "first_name": "User1" 

     }, 
    { 
     "list_of_email_addresses": [ 
      {"email":"[email protected]"} 
      ], 
     "last_name": "", 
     "first_name": "User2" 

    }, 
    { 
     "list_of_email_addresses": [], 
     "last_name": "", 
     "first_name": "User3" 

    } 
    ] 
} 

Если я выполняю код JSon он возвращает , например, он возвращает мне выход

{ 
arr:[ 
     { 
     result : "executed2" 
     } 
    ] 
} 

Я хочу что-то вроде асинхронной природы, я думаю, что он пропускает оставшиеся два.

{ 
arr:[ 
     { 
     result : "executed1" 
     }, 
     { 
     result : "executed1" 
     }, 
     { 
     result : "executed2" 
     } 
    ] 
} 

Вкратце, как я могу обрабатывать асинхронные вызовы для достижения вышеуказанного результата.

+0

Возможный дубликат [JavaScript закрытия внутри петли - простой практический пример] (http://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example) – farhan3

ответ

1

Я лично рекомендую вам ознакомиться с использованием обещаний. Мне повезло с bluebird, и это упрощает аддоны обратного вызова, к которым может перейти узел. Однако, если вы предпочитаете использовать обратные вызовы, проверьте библиотеку async.

Проблема, которую вы видите, заключается в том, что цикл for будет продолжаться до следующего элемента без ожидания обратного вызова. Он также выйдет без ожидания любого обратного вызова. Вы хотите, чтобы каждая итерация выполняла запрос, а затем продолжалась только после завершения запроса.

Редактировать Кроме того, вы видите, что оно возвращается раньше, потому что вы отправляете ответ при первом вызове. Вы хотите, чтобы ждать, пока весь список не был заполнен, а затем отправить ответ (см пример Обещания ниже)

Вот пример использования асинхр:

var async = require("async") 

var userArray = ["mickey mouse", "donald duck", "goofy"]; 
async.eachSeries(userArray, function (user, cb) { 
    doFakeQuery('insert into user_tble set ?', function (err, ins) { 
      doFakeQuery('insert into user_emails (user_id,email_address,) values ?', function (err, ins2) { 
       doFakeQuery('insert into user_phones (user_id,phone_number) values ?', function (err, ins3) { 
        doFakeQuery('insert into user_pictures (user_id,pic_url) values ?', function (err, ins4) { 
         console.log("Finished queries for " + user) 
         cb(); 
        }) 
       }) 
      }) 
     }); 
}, function (err) { 
    console.log("Finished async.map") 
}) 

function doFakeQuery(query, callback) { 
    console.log("Running query '" + query + "'") 
    //Mock an asynchronous callback 
    setTimeout(function() { 
     callback(); 
    }, 300) 
} 

Для сравнения, вот ваш код переписан с Обещания.

var Promise = require("bluebird") 
//Convert conn.query into a function that returns a promise, instead of a callback 
var pQuery = Promise.promisify(conn.query) 

var jsonArray = [] 

Promise.mapSeries(userArray, function (user) { 
    if (user.list_of_emails != undefined) { 
     return addUser(user) 
      .then(addEmails) 
      .then(addPhones) 
      .then(addPictures) 
      .then(function() { 
       jsonArray.push({result: "executed1"}) 
      }) 
    } 
    else if (user.list_of_phones != undefined) { 
     return addPhones() 
      .then(addPictures) 
      .then(function() { 
       jsonArray.push({result: "executed2"}) 
      }) 
    } 
}) 
    .then(function() { 
     console.log("Done!") 
     res.status(200).json(jsonArray) 
    }) 

function addUser(userJSON) { 
    return pQuery('insert into user_tble set ?', userJSON) 
} 

function addEmails() { 
    return pQuery('insert into user_emails (user_id,email_address,) values ?', [globalEmailAddressArray]) 
} 

function addPhones() { 
    return pQuery('insert into user_phones (user_id,phone_number) values ?', [globalPhoneNumberArray]) 
} 

function addPictures() { 
    return pQuery('insert into user_pictures (user_id,pic_url) values ?', ['http://localhost:300/somepicture']) 
} 
+0

спасибо за вывода, но почему мы хотим использовать функцию doFakeQuery? –

+0

Это только для иллюстрации вызова функции с обратным вызовом. Мне нужен код, который запускался бы и показывал вывод функции 'async.eachSeries', но не нуждался бы в соединении с базой данных. Ваш конечный код должен вызвать conn.query(), как обычно. – mdickin

+0

Обратите внимание на новый пример с обещаниями и записью ** Edit **. – mdickin

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