2016-03-27 9 views
1

連鎖約束について質問がありますが、これは少し異なります。 私は自分のコードでHTTPリクエストを取得しています。最初の呼び出しは配列を返します。配列内の各オブジェクトについては、別の配列を返すような別のhttp呼び出しを行う必要があります(この3つのレベルは深く連鎖しています)。 問題は、各http呼び出しを行うためにどの配列要素が使用されたかを把握する必要があり、約束を使用してこれを行う方法がわかりません。 私はまた、約束を返すことによってチェーンを終了したいと思います。連鎖データ(角度j)を維持しながら約束する

私は約束せずにnodejsで書かれて何をしたいのためのコードがあります。

var https = require('https'); 
var fs = require('fs'); 


function makeRequest(options){ 
    var httpopts = { 
    host: 'soc.courseoff.com', 
    path: '/gatech/terms/201601/majors/' + options.p, 
    method: 'GET' 
    }; 
    var response = ""; 
    var req = https.request(httpopts, function(res) { 
     res.on('data', function(d) { 
     response += d; 
     }); 
     res.on('end',function(){ 
     options.cb(response,options) 
     }) 
    }); 

    req.end(); 

    req.on('error', function(e) { 
    console.error(e); 
    }); 
} 
var classData = {}; 
function getCourses(m){ 
    var majors = JSON.parse(m); 
    majors.forEach(function(maj){ 
     classData[maj] = {}; 
     var options = { 
      p:maj.ident +'/courses', 
      cb:getSections, 
      major:maj 
     };  
     makeRequest(options); 
    }); 
} 
var classCount = 0; 
function getSections(c,opts){ 
    var courses = JSON.parse(c); 
    courses.forEach(function(course){ 
     classCount++; 
     var options = JSON.parse(JSON.stringify(opts)); 
     options.p += '/'+course.ident+'/sections'; 
     options.course = course 
     options.cb = buildData 
     makeRequest(options) 
    }); 
} 
var sectionCount = 0; 
function buildData(r, options){ 
    var major = options.major.ident; 
    sectionCount++; 
    if(!classData[major]){ 
     classData[major] = { 
      name: options.major.name, 
      classes:{} 
     }; 
    } 
    classData[major].classes[options.course.ident] = { 
     name:options.course.name, 
     sections:JSON.parse(r) 
    }; 
    console.log('classCount-sectionCount '+classCount + '---'+sectionCount); 
    if(classCount === sectionCount){ 
     writeIt(); 
    } 
} 
makeRequest({ 
    p:'', 
    cb:getCourses 
}); 

function writeIt(){ 
    fs.writeFileSync('./classData.js', 'module.exports = ' + JSON.stringify(classData)); 
} 

はEDIT: データのトラックを維持しながら、私は巣への約束を得ることができたが、どのように私は返すことができますが最終的に最終的なデータオブジェクトで解決される約束ですか? マイコード: ありがとうございました。私は私の唯一の問題は今、ほぼ確実に約束

fact.factory('ClassFactory', ['$http',function ($http) {  
    var eventData = {}; 
     var promise; 
     var courseData = []; 
     var baseURL ='https://soc.courseoff.com/gatech/terms/201601/majors/'; 
     eventData.getClasses = function (event) { 
      if(!promise){ 
       promise = $http.get(baseURL).then(
        function(majors){ 
         Promise.all(majors.data.map(m => $http.get(baseURL + m.ident+'/courses') 
          .then(
           function(courses){ 
            if(!m.courses) m.courses = []; 
            courses.data.map(c => $http.get(baseURL+ m.ident+'/courses/' +c.ident+'/sections') 
             .then(
              function(sections){ 
               c.sections = sections.data; 
               m.courses.push(c); 
              } 
             )); 
            courseData.push(m); 
           } 
          ))); 
        } 
       ) 
      } 
      return promise; 
     } 
     return eventData; 
}]); 

答えて

0

として、最終的なデータを返すにあり、約束が動作するように、それをコードするために管理してきた、あなたは約束の配列を扱うたびに、あなたがしたいですよPromise.allを使用して、あなたの約束を新しい約束に結びつけることができます。その約束は、各呼び出しの結果の配列を含みます。したがって、ネストされたPromise.allsは、マップやクロージャのようなものを使用して外部レベルを取得する限り、結果のすべてのレベルで配列の配列を返すことができます。

var fakeCall = x => Promise.resolve(x||Math.random()); 

Promise.all([fakeCall(1),fakeCall(2)]) 
    .then( 
    results => Promise.all(results.map(x => fakeCall(5).then(results2 => [x, results2]) )) 
) 
    .then(x => console.log(x));//-> [[1,5],[2,5]] 

コールの第1のアレイは、さらによりコールがその親と対にすることができる単一の結果を返すことができる機能を有するものを超える結果のアレイ、およびマッピングを生成します。

このように明示的に入れ子にすることは、さらに深いレベルでも機能しますが、それほど美しくはありません。おそらく、このパターンを一般化できるArray.reduceを使用して作成できる抽象概念があります。

+0

ありがとうございます!私はまだそれを約束として返す問題がある、元の質問を編集した – Noam

+0

あなたはまだPromise.all自体を返す必要があると思います。他のcommenterノートのように、渡されたすべての関数は、値または別のPromiseを返さなければなりません。そうでない場合、返すものはすべて未定義です。 – Dtipson

0

あなたのコードでいくつかの返品を忘れました。 .thenに渡す関数は、常に何かを返す必要があります。 majorsを変更していますが、使用せずに投げ捨ててください。約束事で作業する場合、特に複雑でネストされている場合は、悪いことが起こりそうもない限り、約束事に含まれるデータ構造を変更することはお勧めできません。

私はいくつかの機能に分割します。例:

var baseURL ='https://soc.courseoff.com/gatech/terms/201601/majors/'; 

function getSections(major, course) { 
    return $http.get(baseURL+ major.ident+'/courses/' +course.ident+'/sections') 
       .then(sections => sections.data) 
       .catch(e => []); 
} 

function getCourses(major) { 
    return $http.get(baseURL + major.ident+'/courses') 
       .then(courses => Promise.all(courses.data.map(course => 
       getSections(major, course).then(sections => ({[course.ident]: {name: course.name, sections: sections}}))))) 
       .then(courses => angular.extend({}, ...courses)) 
       .catch(e => ({})); 
} 

function getClassData() { 
    return $http.get(baseURL) 
       .then(majors => Promise.all(majors.data.map(major => 
       getCourses(major).then(courses => ({[major.ident]: {name: major.name, classes: courses}}))))) 
       .then(majors => angular.extend({}, ...majors)) 
       .catch(e => ({})); 
} 

getClassData().then(data => console.log(data)); 
関連する問題