Ten problem jest określany jako "piekło oddzwaniania" .Istnieje wiele innych metod, takich jak użycie Promise i Async biblioteki, które znajdziesz.
Jestem bardziej podekscytowany rodzimymi async
ES7
przyniesie, z której możesz zacząć korzystać już dziś dzięki bibliotece transpilera Babel
.
Ale zdecydowanie najprostsze podejście, jakie znalazłem, jest następujące:Wyjmujesz długie funkcje zwrotne i definiujesz je na zewnątrz.
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
});
}
}
Zastrzeżeniem jest to, że nie będziesz w stanie uzyskać dostępu do wszystkich zmiennych wewnątrz tego, co kiedyś było wywołaniem zwrotnym, ponieważ wyjęłeś je z zakresu.
Można to rozwiązać za pomocą pewnego rodzaju opakowania „wstrzykiwania zależności”, które przekazuje wymagane zmienne.
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
});
}
}
Zdaję sobie sprawę, że popełniłem tutaj błąd:
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);
});
}
Kolejny problem, który mógłbym przewidzieć, który w rzeczywistości może nie pojawić się tutaj, ale i tak lepiej byłoby o nim porozmawiać. data
zmienna, ponieważ jest to ciąg znaków, który w przeciwieństwie do obiektu jest typem pierwotnym, jest „przekazywana przez wartość”. Więcej informacji
Lepiej jest zawinąć zmienną w obiekt i przekazać obiekt, ponieważ obiekty w javascript są zawsze „przekazywane przez referencję”.
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());
...