2016-04-19 12 views
1

私は特定の時間間隔ですべての生徒のデータを取り込み、何らかの条件に達するまで同じプロセスを繰り返す関数を呼び出したいと思います。node.jsと約束を使って同期whileループを書くにはどうすればいいですか?

現在のコードは、関数iterateThruAllStudents()を並列呼び出しするようです。

私のコードは次のようになります。

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

誰もが、私は、各時間間隔のため、同期のすべての学生のためのデータをつかむことができるようなことを達成するためにどのようなアイデアを持っていますか?

+2

現在のコードがうまくいかない理由は明らかではありません。また、[mcve]を提供してください。あなたの質問に関係のないコードは削除してください。 – Shelvacu

+1

私はあなたが 'iterateThruAllStudents'にコールバックを渡して、それが完了したときにコールバックを呼び出さなければならないと思います。 – stefreak

+0

@stefreak何か類似していると思っていましたが、コールバックを置いて、サンプルをくれませんか? –

答えて

0

async.eachSeries()(別名#each())のドキュメントをご覧ください。 3番目の引数を指定して、2番目の関数の引数から発生するコールバックをasync.whilst()とします。

私は次のような変更が必要なことをすると思います。具体的には、私はdoneの名前のコールバックを見てみましょう:

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

サイドノートを、あなたはそれに開いていた場合、私の意見では、このコードにたくさんを単純化するcoまたはasync/awaitようなものを使用しました。

+0

thnx多く、それは完全にうまく動作します:) –

関連する問題