MySQL in NodeJS 是否能够等待全部 query 回传结果才继续执行?
发布于 10 年前 作者 grass0916 13834 次浏览 最后一次编辑是 8 年前 来自 问答

各位午安,方才我在进行 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 的结果。

还麻烦各位前辈协助解答,感谢!

10 回复

用下 eventproxy

@alsotang 谢谢前辈回覆,采用同步类型的套件应该不是解决我当前遇到的问题,我用了一点土法炼钢的方式解决了,看完的话您大概会知道我遇到的问题XD

var SQLQueryCheck = {
	createArrayInit: function (size) {
		var arr = new Array();
		for (var i = 0 ; i < size ; i++)
			arr[i] = false;
		return arr;
	},
	checkedAllQueried: function(arr) {
		for (var i = 0 ; i < arr.length ; i++)
			if (arr[i] === false)
				return false;
		return true;
	}
}


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"));

		var queryChecked = SQLQueryCheck.createArrayInit(coupons.length);

		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'];
							queryChecked[j] = true;
							if (SQLQueryCheck.checkedAllQueried(queryChecked))
								callback(coupons);
						});
					});
				});
			})(i);
		}
	});
}

光看标题我觉得eventproxy可以解决这种问题。eventproxy也是异步的 又不是同步

@wuliao49 抱歉才学疏浅,我想我表达上不够缜密 …

我仔细看了下代码 这是典型的异步回调场景啊。 楼主无非是想 全部query执行完毕再回调,所以自己写了个函数,每次检查各个query的执行状态。 解决方法没问题,不过还是推荐直接eventproxy一行代码就搞定了。 就不用每次自己写函数了。

@wuliao49 前辈谢谢你的再次回覆,如果方便能否帮我起个简单的头,或是告诉我在官网的那个段落呢?

http://html5ify.com/eventproxy/eventproxy.html

顺便,一般在不会遍历所有键的情况下(也就是说不会出特别严谨错误的使用姿势的时候),建议用 = undefined 代替 delete

不过这个是我自己的看法而已,只是推荐这样用。

http://www.smashingmagazine.com/2012/11/05/writing-fast-memory-efficient-javascript/

@xadillax 获益良多,谢谢前辈。

@grass0916 看下面的段落: 重复异步协作

此处以读取目录下的所有文件为例,在异步操作中,我们需要在所有异步调用结束后,执行某些操作。

var ep = new EventProxy(); ep.after(‘got_file’, files.length, function (list) { // 在所有文件的异步执行结束后将被执行 // 所有文件的内容都存在list数组中 }); for (var i = 0; i < files.length; i++) { fs.readFile(files[i], ‘utf-8’, function (err, content) { // 触发结果事件 ep.emit(‘got_file’, content); }); }

更具体的参考github

用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);
        });
    });
};
回到顶部