2016-04-19 4 views
1

Ich möchte eine Funktion aufrufen, die Daten für jeden Schüler für ein bestimmtes Zeitintervall dauert und den gleichen Prozess wiederholen, bis es eine Bedingung erreicht.Wie schreibe ich eine synchrone While-Schleife mit node.js und Versprechen

Der aktuelle Code scheint parallele Aufrufe an die Funktion iterateThruAllStudents();

Mein Code sieht wie folgt aus:

var startDate = new Date("March 16, 2016 00:00:00"); //Start from February 

var fromTimestamp = null; 
var toTimestamp = null; 
var today = new Date(); 
var todayTimestamp = new Date(today).getTime()/1000; 

async.whilst(
    function() { 
     return fromTimestamp < todayTimestamp; 
    }, 
    function (callback) { 
     console.log(startDate); 
     fromTimestamp = new Date(startDate).getTime()/1000; 
     startDate.setDate(startDate.getDate() + 5); 
     toTimestamp = new Date(startDate).getTime()/1000; 
     iterateThruAllStudents(fromTimestamp, toTimestamp); 
     callback(null, startDate); 
    }, 
    function (err, n) { 
     console.log('finished for ' + n); 
    } 
); 

function iterateThruAllStudents(from, to) { 
    Student.find({status: 'student'}) 
     .populate('user') 
     .exec(function (err, students) { 
      if (err) { 
       throw err; 
      } 

      var counter = 0; 
      async.eachSeries(students, function iteratee(student, callback) { 
       if (student.worksnap.user != null) { 
        var worksnapOptions = { 
         hostname: 'api.worksnaps.com', 
         path: '/api/projects/' + project_id + '/time_entries.xml?user_ids=' + student.worksnap.user.user_id + '&from_timestamp=' + from + '&to_timestamp=' + to, 
         headers: { 
          'Authorization': 'Basic ' + auth_hash 
         }, 
         method: 'GET' 
        }; 

        getTimeEntries(worksnapOptions) 
         .then(function (response) { //callback invoked on deferred.resolve 
          return convertXMLToJson(response); 
         }).then(function (timeEntries) { 
          console.log('convert xml to json'); 
          var isEmpty = _.isEmpty(timeEntries); // true 
          if (isEmpty) { 
           callback(null); 
          } 
          return saveTimeEntry(timeEntries); 
         }).then(function (response) { 
          counter++; 
          console.log('all timeEntries for one student finished....Student: ' + student.worksnap.user.user_id + ' Student Counter: ' + counter); 
          callback(null); 
         }); 
       } else { 
        callback(null); 
       } 
      }); 
     }); 
} 

function convertXMLToJson(response) { 
    var deferred = Q.defer(); 
    parser.parseString(response, function (err, results) { 
     if (err) { 
      deferred.reject(err); 
     } 
     var json_string = JSON.stringify(results.time_entries); 
     var timeEntries = JSON.parse(json_string); 
     deferred.resolve(timeEntries); 
    }); 
    return deferred.promise; 
} 

function saveTimeEntry(timeEntries) { 
    var deferred = Q.defer(); 
    _.forEach(timeEntries.time_entry, function (item) { 
     Student.findOne({ 
       'worksnap.user.user_id': item.user_id[0] 
      }) 
      .populate('user') 
      .exec(function (err, student) { 
       if (err) { 
        deferred.reject(err); 
       } 
       student.worksnap.timeEntries.push(item); 
       student.save(function (err) { 
        if (err) { 
         deferred.reject(err); 
        } else { 
         //console.log(item); 
        } 
       }); 

      }); 
    }); 
    deferred.resolve('finished saving timeEntries for one student...'); 

    return deferred.promise; 
} 

function getTimeEntries(requestOptions) { 
    //create a deferred object from Q 
    process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0"; 
    var deferred = Q.defer(); 
    var req = http.request(requestOptions, function (response) { 
     //set the response encoding to parse json string 
     response.setEncoding('utf8'); 
     var responseData = ''; 
     //append data to responseData variable on the 'data' event emission 
     response.on('data', function (data) { 
      responseData += data; 
     }); 
     //listen to the 'end' event 
     response.on('end', function() { 
      //resolve the deferred object with the response 
      console.log('http call finished'); 
      deferred.resolve(responseData); 
     }); 
    }); 

    //listen to the 'error' event 
    req.on('error', function (err) { 
     //if an error occurs reject the deferred 
     console.log('inside On error.'); 
     console.log(err); 
     deferred.reject(err); 
    }); 
    req.end(); 
    //we are returning a promise object 
    //if we returned the deferred object 
    //deferred object reject and resolve could potentially be modified 
    //violating the expected behavior of this function 
    return deferred.promise; 
} 

jemand eine Idee hat, wie man so etwas zu erreichen, die ich Daten für alle Schüler synchron für jedes Zeitintervall greifen?

+2

Es ist nicht ganz klar, warum Ihr aktueller Code nicht funktioniert. Bitte versuchen Sie auch, ein [mcve] zur Verfügung zu stellen. Entfernen Sie jeglichen Code, der für Ihre Frage nicht relevant ist. – Shelvacu

+1

Ich denke, Sie müssen Callback an "iterateThruAllStudents" übergeben und es den Rückruf aufrufen, wenn es fertig ist – stefreak

+0

@stefreak Ich dachte etwas ähnliches, aber ich war nur nicht sicher, wo der Callback die Funktion sagen, dass der Prozess getan wird. Könnten Sie mir eine Probe geben? –

Antwort

0

Werfen Sie einen Blick auf die Dokumentation für async.eachSeries() (Alias ​​von #each()). Sie möchten ein drittes Argument angeben und den Callback aufrufen, der von dem Argument in der zweiten Funktion async.whilst() stammt.

Ich denke, die folgenden Änderungen werden tun, was Sie brauchen. Werfen Sie einen Blick auf den Rückruf I done genannt, insbesondere:

var startDate = new Date("March 16, 2016 00:00:00"); //Start from February 

var fromTimestamp = null; 
var toTimestamp = null; 
var today = new Date(); 
var todayTimestamp = new Date(today).getTime()/1000; 

async.whilst(
    function() { 
     return fromTimestamp < todayTimestamp; 
    }, 
    function (callback) { 
     console.log(startDate); 
     fromTimestamp = new Date(startDate).getTime()/1000; 
     startDate.setDate(startDate.getDate() + 5); 
     toTimestamp = new Date(startDate).getTime()/1000; 
     iterateThruAllStudents(fromTimestamp, toTimestamp, callback); 
    }, 
    function (err, n) { 
     console.log('finished for ' + n); 
    } 
); 

function iterateThruAllStudents(from, to, done) { 
    Student.find({status: 'student'}) 
     .populate('user') 
     .exec(function (err, students) { 
      if (err) { 
       throw err; 
      } 

      var counter = 0; 
      async.eachSeries(students, function iteratee(student, callback) { 
       if (student.worksnap.user != null) { 
        var worksnapOptions = { 
         hostname: 'api.worksnaps.com', 
         path: '/api/projects/' + project_id + '/time_entries.xml?user_ids=' + student.worksnap.user.user_id + '&from_timestamp=' + from + '&to_timestamp=' + to, 
         headers: { 
          'Authorization': 'Basic ' + auth_hash 
         }, 
         method: 'GET' 
        }; 

        getTimeEntries(worksnapOptions) 
         .then(function (response) { //callback invoked on deferred.resolve 
          return convertXMLToJson(response); 
         }).then(function (timeEntries) { 
          console.log('convert xml to json'); 
          var isEmpty = _.isEmpty(timeEntries); // true 
          if (isEmpty) { 
           callback(null); 
          } 
          return saveTimeEntry(timeEntries); 
         }).then(function (response) { 
          counter++; 
          console.log('all timeEntries for one student finished....Student: ' + student.worksnap.user.user_id + ' Student Counter: ' + counter); 
          callback(null); 
         }); 
       } else { 
        callback(null); 
       } 
      }, function eachSeriesFinished(err) { 
       if (err) 
        return done(err); 
       return done(null, to); 
      }); 
     }); 
} 

function convertXMLToJson(response) { 
    var deferred = Q.defer(); 
    parser.parseString(response, function (err, results) { 
     if (err) { 
      deferred.reject(err); 
     } 
     var json_string = JSON.stringify(results.time_entries); 
     var timeEntries = JSON.parse(json_string); 
     deferred.resolve(timeEntries); 
    }); 
    return deferred.promise; 
} 

function saveTimeEntry(timeEntries) { 
    var deferred = Q.defer(); 
    _.forEach(timeEntries.time_entry, function (item) { 
     Student.findOne({ 
       'worksnap.user.user_id': item.user_id[0] 
      }) 
      .populate('user') 
      .exec(function (err, student) { 
       if (err) { 
        deferred.reject(err); 
       } 
       student.worksnap.timeEntries.push(item); 
       student.save(function (err) { 
        if (err) { 
         deferred.reject(err); 
        } else { 
         //console.log(item); 
        } 
       }); 

      }); 
    }); 
    deferred.resolve('finished saving timeEntries for one student...'); 

    return deferred.promise; 
} 

function getTimeEntries(requestOptions) { 
    //create a deferred object from Q 
    process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0"; 
    var deferred = Q.defer(); 
    var req = http.request(requestOptions, function (response) { 
     //set the response encoding to parse json string 
     response.setEncoding('utf8'); 
     var responseData = ''; 
     //append data to responseData variable on the 'data' event emission 
     response.on('data', function (data) { 
      responseData += data; 
     }); 
     //listen to the 'end' event 
     response.on('end', function() { 
      //resolve the deferred object with the response 
      console.log('http call finished'); 
      deferred.resolve(responseData); 
     }); 
    }); 

    //listen to the 'error' event 
    req.on('error', function (err) { 
     //if an error occurs reject the deferred 
     console.log('inside On error.'); 
     console.log(err); 
     deferred.reject(err); 
    }); 
    req.end(); 
    //we are returning a promise object 
    //if we returned the deferred object 
    //deferred object reject and resolve could potentially be modified 
    //violating the expected behavior of this function 
    return deferred.promise; 
} 

Randnotiz, wenn Sie es offen waren, so etwas wie co oder async/await mit einem viel, meiner Meinung nach diesem Code vereinfachen würde.

+0

Thnx viel, es funktioniert völlig in Ordnung :) –

Verwandte Themen