Nodejs中MySQL是否能够等待全部query回传结果才继续执行?
Nodejs中MySQL是否能够等待全部query回传结果才继续执行?
各位午安,方才我在进行 node 上头的 MySQL query,发现了一些问题,请先见程式码如下。
var getAllCouponsInfoByManagerUidAndRange = function (uid, range, callback) {
// Select the special range in coupons, the range object have 'start' and 'amount'.
var sql_1 = "SELECT * FROM coupon WHERE coupon_id BETWEEN " + range.start + " AND " + (range.start + range.amount - 1);
dbclient.query(sql_1, function (err, coupons) {
// Fixed the properties.
coupons = TaskDateConvertToJson(coupons, new Array("create_time", "used_time"));
for (var i = 0 ; i < coupons.length ; i++) {
(function (j) {
// Get the employees' user info of having received coupons.
findUserByUid(coupons[j].uid, function (employee) {
// Get the managers of creating coupons.
findUserByUid(coupons[j].manager, function (manager) {
// Get the employees' task info of having received coupons.
findTaskByTid(coupons[j].tid, function (task) {
coupons[j]['employee'] = employee;
coupons[j]['manager'] = manager;
coupons[j]['task'] = task;
delete coupons[j]['uid'];
delete coupons[j]['tid'];
if (j == coupons.length - 1)
callback(coupons);
console.log(coupons[j]);
});
});
});
})(i);
}
});
}
其中有一行
console.log(coupons[j]);
是用来检查 query 的执行完毕顺序,
假使目前情况是 15 笔到 30 笔,因为部分条件不同,console.log 的结果会发现
15, 16, 18, 19, … , 30, 17。
第 17 笔经过较多层的 query 所以回传的时间较久,因为这样:
if (j == coupons.length - 1)
callback(coupons);
在完成第 30 笔时就执行 callback …其中回传的第 17 笔是没有 query 的结果。
还麻烦各位前辈协助解答,感谢!
在Node.js中处理异步操作时,特别是涉及到数据库查询时,经常会遇到类似的问题。为了确保所有的查询都完成后再执行下一步操作,我们可以使用Promise
或者async/await
来更好地管理这些异步操作。
下面是改进后的代码示例,使用async/await
来确保所有的查询都完成后再调用回调函数:
const mysql = require('mysql');
const dbclient = mysql.createConnection({
host: 'localhost',
user: 'root',
password: 'password',
database: 'database_name'
});
const findUserByUid = async (uid) => {
return new Promise((resolve, reject) => {
dbclient.query("SELECT * FROM users WHERE uid = ?", [uid], (err, results) => {
if (err) reject(err);
resolve(results[0]);
});
});
};
const findTaskByTid = async (tid) => {
return new Promise((resolve, reject) => {
dbclient.query("SELECT * FROM tasks WHERE tid = ?", [tid], (err, results) => {
if (err) reject(err);
resolve(results[0]);
});
});
};
const getAllCouponsInfoByManagerUidAndRange = async (uid, range) => {
try {
// Select the special range in coupons, the range object have 'start' and 'end'.
const sql_1 = "SELECT * FROM coupon WHERE coupon_id BETWEEN ? AND ?";
const [coupons] = await dbclient.query(sql_1, [range.start, range.start + range.amount - 1]);
// Convert the date fields to JSON format
coupons = TaskDateConvertToJson(coupons, ["create_time", "used_time"]);
// Process each coupon
for (let j = 0; j < coupons.length; j++) {
const [employee] = await findUserByUid(coupons[j].uid);
const [manager] = await findUserByUid(coupons[j].manager);
const [task] = await findTaskByTid(coupons[j].tid);
coupons[j]['employee'] = employee;
coupons[j]['manager'] = manager;
coupons[j]['task'] = task;
delete coupons[j]['uid'];
delete coupons[j]['tid'];
console.log(coupons[j]);
}
return coupons;
} catch (error) {
console.error(error);
}
};
getAllCouponsInfoByManagerUidAndRange(uid, range)
.then(coupons => {
console.log('All queries completed:', coupons);
})
.catch(error => {
console.error('Error occurred:', error);
});
function TaskDateConvertToJson(data, fields) {
data.forEach(item => {
fields.forEach(field => {
item[field] = JSON.stringify(item[field]);
});
});
return data;
}
解释
- 使用
async/await
:通过将查询封装成返回Promise
的函数(如findUserByUid
和findTaskByTid
),我们可以在主逻辑中使用await
关键字来等待这些查询完成。 - 循环处理:在循环中,每个查询都是异步的,但通过
await
关键字,我们可以确保在处理下一个查询之前,当前查询已经完成。 - 错误处理:使用
try/catch
结构来捕获和处理可能发生的错误。
这种方法确保了所有的查询都按顺序完成,并且只有在所有查询都成功完成后才会调用回调函数。
用下 eventproxy
光看标题我觉得eventproxy可以解决这种问题。eventproxy也是异步的 又不是同步
我仔细看了下代码 这是典型的异步回调场景啊。 楼主无非是想 全部query执行完毕再回调,所以自己写了个函数,每次检查各个query的执行状态。 解决方法没问题,不过还是推荐直接eventproxy一行代码就搞定了。 就不用每次自己写函数了。
顺便,一般在不会遍历所有键的情况下(也就是说不会出特别严谨错误的使用姿势的时候),建议用 = undefined
代替 delete
。
不过这个是我自己的看法而已,只是推荐这样用。
http://www.smashingmagazine.com/2012/11/05/writing-fast-memory-efficient-javascript/
用howdo帮你重写了一遍
var howdo = require('howdo');
var getAllCouponsInfoByManagerUidAndRange2 = function(uid, range, callback) {
// Select the special range in coupons, the range object have 'start' and 'amount'.
var sql_1 = 'SELECT * FROM coupon WHERE coupon_id BETWEEN ' + range.start + ' AND ' + (range.start + range.amount - 1);
dbclient.query(sql_1, function(err, coupons) {
if (err) {
return callback(err);
}
// Fixed the properties.
var coupons = TaskDateConvertToJson(coupons, ['create_time', 'used_time']);
howdo.each(coupons, function(index, coupon, done) {
howdo
// Get the employees' user info of having received coupons.
.task(function(done) {
findUserByUid(coupon.uid, function(employee) {
done(null, employee);
});
})
// Get the managers of creating coupons.
.task(function(done) {
findUserByUid(coupon.manager, function(manager) {
done(null, manager);
});
})
// Get the employees' task info of having received coupons.
.task(function(done) {
findTaskByTid(coupon.tid, function(task) {
done(null, task);
});
})
// 并行无依赖结果
.together(function(err, employee, manager, task) {
coupon.employee = employee;
coupon.manager = manager;
coupon.task = task;
delete coupon.uid;
delete coupon.tid;
done(null, coupon);
});
}).together(function(err, create_time, used_time) {
// 做你该做的
// ....
callback(err, create_time, used_time);
});
});
};