2012-10-10 8 views
5

Tôi muốn hỏi câu hỏi này, bởi vì tôi không chắc chắn nếu tôi có logic Node.js đúngNode.js & Redis; Chờ đợi một vòng lặp để kết thúc

tôi có một tập hợp của id mà tôi cần để truy vấn sử dụng redis' get phương pháp. Và sau khi kiểm tra một giá trị nào đó (giả sử rằng im kiểm tra xem đối tượng tôi nhận được với "khóa" đã cho có một tên rỗng), tôi thêm chúng vào một danh sách. Đây là mã ví dụ của tôi;

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

Nhưng như mong đợi do bản chất async của Node, mà không kiểm tra tất cả các id duy nhất trong danh sách nó thực thi các "Goes ở đây ...". Nhu cầu của tôi là áp dụng các thủ tục còn lại sau mỗi lần kiểm tra id (ánh xạ trong redis db và kiểm tra tên). Nhưng tôi không biết làm thế nào để làm điều đó. Có lẽ nếu tôi có thể đính kèm gọi lại cho vòng lặp và đảm bảo phần còn lại của các chức năng của tôi bắt đầu chạy sau khi vòng lặp kết thúc (tôi biết nó không thể, nhưng chỉ để đưa ra một ý tưởng)?

Trả lời

4

tôi sẽ đi con đường bạn đề nghị trong câu hỏi của bạn và đính kèm một callback tùy chỉnh chức năng quyến rũ của bạn:

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

Đó có thể là phương pháp hiệu quả nhất; Hoặc bạn có thể dựa vào một tuổi học while vòng lặp cho đến khi dữ liệu đã sẵn sàng:

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

Chúng tôi sử dụng process.nextTick thay vì một thực tế while để đảm bảo các yêu cầu khác không bị chặn trong khi chờ đợi; do tính chất luồng đơn của Javascript, đây là cách được ưu tiên. Tôi đang ném điều này vì lợi ích của sự hoàn chỉnh, nhưng phương pháp trước đây hiệu quả hơn và phù hợp hơn với node.js, vì vậy hãy thực hiện nó trừ phi có viết lại chính.

Không có gì đáng kể khi cả hai trường hợp dựa vào các cuộc gọi lại không đồng bộ, có nghĩa là bất kỳ mã nào bên ngoài nó vẫn có khả năng chạy trước khi những người khác được thực hiện. Ví dụ, sử dụng đoạn mã đầu tiên của chúng tôi:

function getStudentsData(callback) { 
    //[...] 
} 

getStudentsData(function(dataList) { 
    //[...] 
}); 

console.log("hello world"); 

Đó console.log cuối cùng gần như được đảm bảo để chạy trước khi gọi lại của chúng tôi truyền cho getStudentsData bị sa thải. Cách giải quyết? Thiết kế cho nó, nó chỉ là cách node.js hoạt động. Trong trường hợp của chúng tôi ở trên dễ dàng, chúng tôi chỉ gọi console.log chỉ trong cuộc gọi lại được chuyển tới getStudentsData chứ không phải bên ngoài nó. Các tình huống khác yêu cầu các giải pháp khởi hành nhiều hơn một chút so với mã hóa thủ tục truyền thống, nhưng một khi bạn có được đầu xung quanh nó, bạn sẽ thấy sự kiện định hướng và không chặn thực sự là một tính năng khá mạnh.

+0

dụ đầu tiên dường như không làm việc cho tôi :(Xem [này] (https://i.gyazo.com/129b071f39bbd1a1c491638be634b00c.png), cuộc gọi redis là không đồng bộ Các. Nhật ký giao diện điều khiển của 'kết quả' của tôi sẽ được hiển thị đầu tiên vì nó là logic chính xác giống như trong ví dụ của bạn, hmmm –

1

Hãy thử async mô-đun cho node.js. Mô-đun đó có forEach không đồng bộ.

3

Thử mô-đun finish. Tôi đã tạo ra mô-đun này để giải quyết vấn đề này. Nó dễ sử dụng hơn Async và cũng mang lại hiệu suất tốt hơn. Dưới đây là một ví dụ:.

var finish = require("finish"); 
finish(function(async) { 
    // Any asynchronous calls within this function will be captured 
    // Just wrap each asynchronous call with function 'async' 
    ['file1', 'file2', 'file3'].forEach(function(file) { 
    async(function(done) { 
     // Your async function should use 'done' as callback, or call 'done' in its callback 
     fs.readFile(file, done); 
    }); 
    }); 
}, function(err, results) { 
    // fired after all asynchronous calls finish or as soon as an error occurs 
    console.log(results[0]);console.log(results[1]);console.log(results[2]); 
}); 
+2

Nên đăng mẫu mã cũng như liên kết. Bằng cách đó, nếu liên kết trở nên chết thì bài đăng không phải là vô dụng. – Matthew

+0

Cảm ơn Mã mẫu được thêm – Chaoran

+1

WARN: 'finish' hiện đang chokes nếu mảng bạn' forEach' trống, và thoát với "TypeError: không thể đọc được thuộc tính 'kickoff' của undefined". xuống, hy vọng nó tiết kiệm cho người khác một số đau đớn![Xem vấn đề trên Github] (https://github.com/chaoran/node-finish/issues/2). – OJFord