在 User_UidSearch 函式当中我想要取用上一层 for 回圈的i ,但没有办法,这个 i 的scope 让我有点疑惑,不晓得各位前辈有没有不使用全域变数的解决办法呢?
Task_TidSearchExecution = function(tid, callback) {
    var sql = "SELECT * FROM execution WHERE task = '" + tid + "'";
    dbclient.query(sql, function (err, results) {
        if (err || results.length <= 0)
            callback(false);
        else {
            console.log(results.length);
            for (var i = 0 ; i < results.length ; i++) {
                User_UidSearch(results[i].employee, function (user) {
                    console.log(i);
                    // results[i]['email'] = user.email;
                });
            }
            
            callback(results);
        }
    });
}
console.log(result[i]); 输出都是 undefined。 如果我的 results.length 为 2,console.log(i); 都是 2
      17 回复
    
    经典问题。
for (var i = 0 ; i < results.length ; i++) {
  (function (j) {
    User_UidSearch(results[j].employee, function (user) {
        console.log(j);
        // results[j]['email'] = user.email;
    });
  })(i);
};
经过前辈们指教,解决的上述的问题,以及衍生出来的问题。
程式码如下,不过觉得可读性有点低,想请教有没有更精炼的优化方式。
Task_TidSearchExecution = function(tid, callback) {
    var sql = "SELECT * FROM execution WHERE task = '" + tid + "'";
    dbclient.query(sql, function (err, results) {
        if (err || results.length <= 0)
            callback(false);
        else {
            AddEmployeesInfo(function (results) {
                console.log(results);
                callback(results);
            });
            function AddEmployeesInfo(callback) {
                for (var i = 0 ; i < results.length ; i++) {
                    (function (j) {
                        User_UidSearch(results[j].employee, function (user) {
                            results[j]['uid'] = user.uid;
                            results[j]['email'] = user.email;
                            if (j == results.length-1)
                                callback(results);
                        });
                    })(i);
                }
            };
        }
    });
}
我有几个建议。
对于 Task_TidSearchExecution = function(tid, callback):
- 改成var Task_TidSearchExecution = function(tid, callback);
- 函数的命名风格保持一致,参照下面的AddEmployeesInfo,把Task_TidSearchExecution改为findExecutionTaskById更自然点;
- 这里的函数参数callback没有遵循Node.js的例行写法。一般来说,callback函数都被定义成callback(err, arg1, arg2, ...)的形式。因此,建议把callback的函数原型修改为callback(err, results);
- 函数体里,if (err || results.length<=0)中没必要添加results.length<=0的判断;
- else部分,- AddEmployeesInfo函数的定义似乎是多此一举,直接在- else下面写- for循环的语句就可以了;
- 不了解数据库表和User_UidSearch函数的定义,更多优化无从下手。感觉有进一步优化的空间。
@bnuhero 前辈早安,根据你宝贵的建议我尝试做了一些更动,还请你审视一番。
- “Task_” 系列函数是 SQL query 用途,所以他们本身是属最外层,所以我就没有多留意加上var,虽然不影响结果但想起曾经看过一篇文章「变数通通都加上var」这类的观念。
- 对,其实一致也会比较好,那我就更改了。
- 这点其实我不太清楚,麻烦你再帮忙解释了 ><
- 由于 query 的结果可能会有程式码执行成功但无资料回传,所以仍必须写上 length == 0,不过我改了一下写法,可以看看文后的程式码。
- 逻辑问题,抱歉还不是很熟callback,我修正了@@
- 于后面附上
/* =============================================
          Task - Employer maintain tasks
   ============================================= */
app.get('/maintain_task', function (req, res) {
    // Users can see this page when them logged-in.
    if (req.session) {
        var user = { "uid": req.session.uid, "email": req.session.email };
        var query_tid = req.query.tid;
        findEmployerByTid(query_tid, function (manager) {
            // If this task manager matches on user's id.
            if (manager !== false && user.uid === manager) {
                // Get the task info.
                findTaskByTid(query_tid, function (task) {
                    // Get these executions info with employees' info.
                    findExecutionTaskByTid(task.tid, function (employees) {
                        res.render("task_system/maintain_task", {
                            layout: false,
                            pagename: "Page Name",
                            user: user,
                            task: task,
                            employees: employees,
                            errormessage: "null"
                        });
                    });
                });
            }
            // If this task manager no matches on user's id.
            else
                res.redirect('/employer_task_list');
        });
    }
    // Users must log in first.
    else
        res.redirect('/login');
});
var findExecutionTaskByTid = function(tid, callback) {
    var sql = "SELECT * FROM execution WHERE task = '" + tid + "'";
    dbclient.query(sql, function (err, results) {
        if (err)
            callback(false);
        else if (results.length == 0)
            callback(new Array());
        for (var i = 0 ; i < results.length ; i++) {
            (function (j) {
                findUserByUid(results[j].employee, function (user) {
                    results[j]['uid'] = user.uid;
                    results[j]['email'] = user.email;
                    if (j == results.length-1)
                        callback(results);
                });
            })(i);
        }
    });
}
var findUserByUid = function (uid, callback) {
    var sql = "SELECT * FROM user WHERE uid = '" + uid + "'";
    dbclient.query(sql, function (err, results) {
        if (err || results.length <= 0)
            callback(false);
        else
            callback(results[0]);
    });
}
var findTaskByTid = function (tid, callback) {
    var sql = "SELECT * FROM task WHERE tid = '" + tid +"'";
    dbclient.query(sql, function (err, results) {
        if (err || results.length <= 0)
            callback(false);
        else
            callback(results[0]);
    });
}
var findEmployerByTid = function (tid, callback) {
    var sql = "SELECT employer FROM task WHERE tid = '" + tid +"'";
    dbclient.query(sql, function (err, results) {
        if (err || results.length <= 0)
            callback(false);
        else
            callback(results[0].employer);
    });
}

关于回调函数的惯常写法,举个例子。
// 通常回调函数的第一个参数是一个Error对象。
var printNumber = function(err, num) {
  if (err) {
    console.error(err);
  } else {
    console.log(num);
 };
};
// 主函数
var getNumber = function(callback) {
  // 从数据库中读取数据
  // 如果读取过程中出错了,
     callback(new Error('Something is wrong'));
  // 否则,假设读到的数据保存在num变量中,
     callback(null, num);
};
// 调用主函数
getNumber(printNumber);
像你的代码中的callback,把代表出错信息的对象和正常结果的对象用同一个参数表示,不符合如上所述的惯常用法。
 
       
       
       
       
       
    