Sự cố này được gọi là "địa ngục gọi lại" .Có rất nhiều cách tiếp cận khác như sử dụng Promise và Async thư viện bạn sẽ tìm thấy.
Tôi hào hứng hơn với async
ES7
sẽ mang lại, mà bạn thực sự có thể bắt đầu sử dụng ngay hôm nay với thư viện chuyển tiếp Babel
.
Nhưng cho đến nay, cách tiếp cận đơn giản nhất mà tôi đã tìm thấy là như sau:Bạn lấy ra các hàm gọi lại dài và định nghĩa chúng bên ngoài.
router.route('/report') // the REST api address
.post(calling_a_POST)
function calling_a_POST(req, res) {
...
var data = "";
https.get(url, function callback(response) {
...
response.on("end", response_on_end_callback); // --> take out
response.on("error", console.error);
});
}
function response_on_end_callback() { // <-- define here
...
for (var i = 0; i < length; i++) {
var report = new Report(array.pop());
...
Report.find({ id: report['id'] })
.count(Report_find_count_callback); // --> take out
};
res.json({
message: 'Grabbed Report'
});
}
function Report_find_count_callback(err, count) { // <-- define here
...
if (count == 0) {
report.save(function(err) { // !! report is undefined here
console.log('saved');
if (err)
res.send(err); // !! res is undefined here
});
}
}
Một lưu ý là bạn sẽ không thể truy cập tất cả các biến bên trong những gì đã từng là lệnh gọi lại, bởi vì bạn đã đưa chúng ra khỏi phạm vi.
Điều này có thể được giải quyết bằng một trình bao bọc "phụ thuộc vào" các loại để chuyển các biến được yêu cầu.
router.route('/report') // the REST api address
.post(calling_a_POST)
function calling_a_POST(req, res) {
...
var data = "";
https.get(url, function callback(response) {
...
response.on("end", function(err, data){ // take these arguments
response_on_end(err, data, res); // plus the needed variables
});
response.on("error", console.error);
});
}
function response_on_end(err, data, res) { // and pass them to function defined outside
...
for (var i = 0; i < length; i++) {
var report = new Report(array.pop());
...
Report.find({ id: report['id'] })
.count(function(err, count){
Report_find_count(err, count, report, res); // same here
});
};
res.json({ // res is now available
message: 'Grabbed Report'
});
}
function Report_find_count(err, count, report, res) { // same here
...
if (count == 0) {
report.save(function(err) { // report is now available
console.log('saved');
if (err)
res.send(err); // res is now available
});
}
}
Tôi nhận ra mình đã mắc lỗi ở đây:
function calling_a_POST(req, res) {
...
var data = "";
https.get(url, function callback(response) {
...
//sponse.on("end", function(err, data){
response.on("end", function(err){ // data shouldn't be here
response_on_end(err, data, res);
});
response.on("error", console.error);
});
}
Một vấn đề khác mà tôi có thể nhận thấy, thực sự có thể không phát sinh ở đây nhưng vẫn tốt hơn nên nói về mọi thứ. data
biến, vì đó là một chuỗi là kiểu nguyên thủy không giống đối tượng, nó được "truyền theo giá trị". Thông tin thêm
Tốt hơn là nên bọc biến trong một đối tượng và chuyển đối tượng, vì các đối tượng trong javascript luôn được "truyền bằng tham chiếu".
function calling_a_POST(req, res) {
...
// var data = ""; //
var data_wrapper = {};
data_wrapper.data = {}; // wrap it in an object
https.get(url, function callback(response) {
...
response.on("data", function(chunk){
data_wrapper.data += chunk.toString() + ""; // use the dot notation to reference
});
response.on("end", function(err){
response_on_end(err, data_wrapper, res); // and pass that object
});
response.on("error", console.error);
});
}
function response_on_end_callback(err, data_wrapper, res) {
var data = data_wrapper.data; // later redefine the variable
...
for (var i = 0; i < length; i++) {
var report = new Report(array.pop());
...