我想问这个问题,因为我不确定我是否正确使用了Node.js逻辑
我有一组ID,需要使用redis的get方法进行查询。在检查了某个值之后(假设我正在检查通过给定的“键”获取的对象是否具有空名称),然后将它们添加到列表中。这是我的示例代码;
var finalList = []; var list = []; redisClient.smembers("student_list", function(err,result){ list = result; //id's of students console.log(result); var possibleStudents = []; for(var i = 0; i < list.length; i++){ redisClient.get(list[i], function(err, result){ if(err) console.log("Error: "+err); else{ tempObject = JSON.parse(result); if(tempObject.name != null){ finalList.push(tempObject); } } }); } }); console.log("Goes here after checking every single object");
但是由于Node的异步特性,正如预期的那样,如果不检查列表中的每个id,它将执行“ Goes here …”。我的需要是在检查每个id之后应用其余过程(在redis db中进行映射并检查名称)。但是我不知道该怎么做。也许我可以将回调附加到for循环并确保其余功能在循环结束后开始运行(我知道这是不可能的,但只是给出一个想法)?
我会按照您在问题中建议的路线进行操作,并将自定义回调附加到您的提取函数中:
function getStudentsData(callback) { var setList = []; var dataList = []; redisClient.smembers("student_setList", function(err,result) { setList = result; //id's of students for(var i = 0; i < setList.length; i++) { redisClient.get(setList[i], function(err, result) { if(err) { console.log("Error: "+err); } else { tempObject = JSON.parse(result); if(tempObject.name != null) { dataList.push(tempObject); } } }); } if(dataList.length == setList.length) { if(typeof callback == "function") { callback(dataList); } console.log("getStudentsData: done"); } else { console.log("getStudentsData: length mistmach"); } }); } getStudentsData(function(dataList) { console.log("Goes here after checking every single object"); console.log(dataList.length); //More code here });
那可能是最有效的方法。或者,您可以依靠旧的while循环,直到数据准备就绪:
while
var finalList = []; var list = [0]; redisClient.smembers("student_list", function(err,result) { list = result; //id's of students var possibleStudents = []; for(var i = 0; i < list.length; i++) { redisClient.get(list[i], function(err, result) { if(err) { console.log("Error: "+err); } else { tempObject = JSON.parse(result); if(tempObject.name != null) { finalList.push(tempObject); } } }); } }); process.nextTick(function() { if(finalList.length == list.length) { //Done console.log("Goes here after checking every single object"); console.log(dataList.length); //More code here } else { //Not done, keep looping process.nextTick(arguments.callee); } });
我们使用process.nextTick而不是实际的方法while来确保在此期间其他请求不会被阻止;由于Javascript具有单线程特性,因此这是首选方式。为了完整起见,我将其放入其中,但是前一种方法效率更高,并且更适合与node.js配合,因此,除非涉及重大重写,否则请继续进行下去。
process.nextTick
两种情况都依赖异步回调是毫无价值的,这意味着它之外的任何代码仍然可以在其他代码完成之前运行。例如,使用我们的第一个片段:
function getStudentsData(callback) { //[...] } getStudentsData(function(dataList) { //[...] }); console.log("hello world");
几乎可以保证最后一个console.log在触发传递给getStudentsData的回调之前可以运行。解决方法?为此进行设计,这就是node.js的工作方式。在上面的例子中,这很容易,我们 只 在传递给getStudentsData的回调中调用console.log ,而不在其外部调用。其他场景要求的解决方案与传统的过程编码有更多的区别,但是一旦掌握了这一点,您就会发现事件驱动和非阻塞实际上是一个非常强大的功能。