在 node.js 中处理对查询的异步调用

Handling asynchronous calls on queries in 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":"user1@user1.com"} 
              ],
            "last_name": "",
            "first_name": "User1"

       },
  { 
      "list_of_email_addresses": [ 
          {"email":"user2@user2.com"} 
          ],
      "last_name": "",
        "first_name": "User2"

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

  }
    ]
}

如果我执行 json 代码 returns 例如它 returns 我输出

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

我想要类似的东西,由于异步性质,我认为它会跳过剩下的两个。

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

简而言之,我如何处理异步调用以实现上述输出。

我个人建议您考虑使用 Promises。我在 bluebird and it simplifies the callback hell that node can turn into. However, if you'd rather stick with callbacks, check out the async 图书馆方面很幸运。

您看到的问题是 for 循环将继续到下一个项目而不等待回调。它也会退出而不等待 any 回调。您希望每次迭代 运行 查询,然后仅在查询完成后继续。

编辑 此外,您会提前 return 看到它,因为您在第一次调用时发送了响应。您想等到整个列表都已填充,然后发送响应(请参阅下面的 Promises 示例)

下面是一个使用异步的例子:

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)
}

为了比较,这里是用 Promises 重写的代码。

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'])
}