2016-03-27 12 views
1

Ich habe gesehen, dass es Fragen zu Verkettung Versprechungen gibt, aber dieses ist ein bisschen anders. Ich mache http get Anfragen in meinem Code. Der erste Aufruf gibt ein Array zurück. Für jedes Objekt im Array muss ich einen weiteren http-Aufruf machen, der ein anderes Array zurückgibt usw. (dies kettet 3 Ebenen tief). Das Problem ist, ich muss verfolgen, welche Array-Element wurde für jeden HTTP-Aufruf verwendet, und ich weiß nicht, wie dies mit Versprechen zu tun. Ich möchte auch die Kette durch die Rückgabe eines Versprechens beenden.Verkettung Versprechen, während die Daten beibehalten (Winkel js)

Ich habe den Code für das, was ich in NodeJS ohne Versprechungen geschrieben wollen:

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: ich es geschafft, die Versprechungen zu Nest zu bekommen, während die Übersicht über die Daten zu halten, aber wie kann ich zurückkehren ein Versprechen, das schließlich mit dem endgültigen Datenobjekt gelöst wird? Mein Code: Dank vier Ihrer Hilfe! Ich habe es geschafft, es so zu codieren, dass die Versprechungen arbeiten, mein einziges Problem ist jetzt in die endgültigen Daten als ein Versprechen der Rückkehr

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

Antwort

0

Fast sicher, jedes Mal, wenn Sie mit einer Reihe von Versprechungen beschäftigen, werden Sie wollen Promise.all zu verwenden, um deine Versprechen in ein neues Versprechen zu verbinden und zusammenzuführen. Dieses Versprechen wird dann ein Array der Ergebnisse von jedem Anruf enthalten. Verschachtelte Promise.alls können somit Arrays von Arrays mit allen Ebenen von Ergebnissen zurückgeben, solange Sie so etwas wie eine Karte und eine Schließung verwenden, um die äußeren Ebenen zu erfassen.

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]] 

die erste Anordnung von Anrufen erzeugt eine Reihe von Ergebnissen, und Kartierung über die, mit einer Funktion, die noch mehr Anrufe ein einzelnes Ergebnis kehren macht, das mit seinem übergeordneten gepaart werden kann.

Das explizite Verschachteln von Dingen auf diese Weise funktioniert auf noch tieferen Ebenen, wird aber nicht schön sein. Es gibt wahrscheinlich eine Abstraktion, die Sie mit Array.reduce erstellen können, die dieses Muster verallgemeinern kann.

+0

Danke für die Hilfe! Ich habe immer noch Probleme, es als Versprechen zurückzugeben, ich habe die ursprüngliche Frage bearbeitet – Noam

+0

Sie müssen immer noch die Promise.all selbst, denke ich. Wie der andere Kommentator feststellt, MÜSSEN alle Funktionen, die übergeben werden, entweder einen Wert oder ein anderes Versprechen zurückgeben: Sonst sind alle, die Sie zurückgeben, undefiniert. – Dtipson

0

Sie haben einige Rückgaben in Ihrem Code vergessen. Die Funktion, die Sie an .then übergeben, sollte immer etwas zurückgeben. Auch Sie ändern majors, aber dann werfen Sie es weg, ohne es zu verwenden. Wenn Sie mit Versprechen arbeiten - insbesondere wenn sie komplex und verschachtelt sind - ist es keine gute Idee, die in diesen Versprechen enthaltenen Datenstrukturen zu ändern, es sei denn, Sie sind sicher, dass nichts Schlimmes passieren kann.

Ich würde es in mehrere Funktionen teilen. z.B.

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)); 
Verwandte Themen