2016-06-24 3 views
0

Ich versuche, durch eine Reihe von HAL/JSON-Ressourcen zu durchlaufen, die einen Baum von Elementen modelliert über hrefs verbunden und über HTTPS abgerufen. I.e. ein "Gegenstand" kann ein Urlaub oder ein anderer Zweig mit anderen Blättern sein. Ach, ich kann es nicht richtig machen. Die Durchquerung wird immer enden, d. H. Den Rückruf then() in der letzten Anweisung meines Codebeispiels treffen, bevor die vollständige Rekursion durchgeführt wurde. In der Tat bekomme ich nur die erste Schicht in Kindern zurück.Async HTTP (S) Traversal nur mit Node.js Promisses

Meine Frage: Was habe ich vermisst, um es richtig zu machen?

Ich lerne immer noch Nodejs, aber ich habe Versprechen in früheren Beispielen erfolgreich verwendet. Ich stelle die Frage hier, weil ich nur das Modul https und das integrierte Nodejs Zeug verwenden muss. Andere Beispiele verwenden oft andere Module und/oder lösen das Problem nicht, das ich habe.

var traverse = function(rootItemUrl, depth, children) { 
    var deferred = Promise.defer(); 

    var itemUrl = rootItemUrl; 
    var options = { 
     'path'  : itemUrl 
     , 'host'  : "<host>" 
     , 'method' : 'GET' 
     , 'headers' : { 
      'Content-Type' : 'application/json' 
      , 'Accept'  : 'application/json' 
      , 'Forwarded' : 'proto=https;host=<host>' 
      , 'Cookie'  : options_.headers['Cookie'] 
     } 
    }; 

    https.get(options, onItemResultResponse); 
    function onItemResultResponse(itemResultResponse) { 
     var body = []; 
     itemResultResponse.on('data', function onDataChunk(data) { 
      body.push(data); 
     }); 
     itemResultResponse.on('end', onItemResultData); 
     itemResultResponse.on('error', onRequestItemsError); 
     function onRequestItemsError(e) { 
      console.log('Get items failed for <'+rootItemUrl+'>.'); 
      deferred.reject(); 
     } 
     function onItemResultData() { 
      var items = []; 
      var itemResult = JSON.parse(Buffer.concat(body).toString()); 
      var embedded = itemResult._embedded; 
      var collection = embedded ? embedded['collection'] : undefined; 
      if(collection) { 
       var itemsObject = collection._links['item']; 
       if(itemsObject) { 
        if(itemsObject.length) { 
         for(var i = 0; i < itemsObject.length; ++i) { 
          items.push(itemsObject[i].href); 
         } 
        } else { 
         items.push(itemsObject.href); 
        } 
       } 
      } 

      var type = itemResult.base.type; 
      var name = itemResult.common.name; 

      var text = repeatChar(depth, '\t') + ('folder' === type ? '- (folder) ' : '')+ 'depth: '+depth+' '+name; 
      children.push(text); 
      //console.log(text); 

      if(items.length) { 
       for (var j = 0; j < items.length; ++j) { 
        traverse(items[j], depth + 1, children) 
         .then(function() {deferred.resolve(depth);}); 
       } 
      } else { 
       deferred.resolve(depth); 
      } 
     } 
    } 

    return deferred.promise; 
}; 

var children = []; 
traverse(rootItemUrl, 0, children) 
         .then(function toConsole(depth) { 
          // >> Alas I hit this point too early << 
          console.log(children); 
          console.log('End'); 
         }); 

Antwort

0

Wer auch immer in einer Antwort auf diese Frage interessiert ist, lesen Sie bitte weiter, weil ich eine Lösung ohne Versprechungen gefunden. Ich habe Versprechen zugunsten von Rückrufen komplett abgeschafft. Bitte beachten Sie, dass ich einige Änderungen im Vergleich zum ursprünglichen Code, z. Sammeln von Ergebnissen, anstatt sie im rekursiven Code zu stdout zu drucken, und ich entfernte einige andere Flusen.

var traverse = function(options, rootItemUrl, depth, done) { 
    var results = []; 

    options.path = rootItemUrl; 
    https.get(options, onItemResultResponse); 
    function onItemResultResponse(itemResultResponse) { 
     var body = []; 
     itemResultResponse.on('data', function onDataChunk(data) { 
      body.push(data); 
     }); 
     itemResultResponse.on('end', onItemResultData); 
     itemResultResponse.on('error', onRequestItemsError); 
     function onRequestItemsError(e) { 
      console.log('Get items failed for <' + rootItemUrl + '>.'); 
      done(e); 
     } 
     function onItemResultData() { 
      var items = []; 
      var itemResult = JSON.parse(Buffer.concat(body).toString()); 

      var embedded = itemResult._embedded; 
      results.push(toItemInfo(itemResult, depth)); 
      var collection = embedded ? embedded['collection'] : undefined; 
      var embeddedItems = collection ? collection._embedded : undefined; 
      if (embeddedItems) { 
       var itemsObject = embeddedItems['item']; 
       if (itemsObject) { 
        if (itemsObject.length) { 
         for (var i = 0; i < itemsObject.length; ++i) { 
          items.push(itemsObject[i]); 
         } 
        } else { 
         items.push(itemsObject); 
        } 
       } 

       var itemInfos = new Array(items.length); 
       for (var iii = 0; iii < items.length; ++iii) { 
        itemInfos[iii] = toItemInfo(items[iii], depth + 1); 
       } 

       var ii = 0; 
       (function next() { 
        var nextItemInfo = itemInfos[ii++]; 
        if (!nextItemInfo) { 
         return done(null, results); 
        } 
        if ('folder' === nextItemInfo.type) { 
         traverse(options, nextItemInfo, depth + 1, function done(err, result) { 
          results = results.concat(result); 
          next(); 
         }); 
        } else { 
         results.push(nextItemInfo); 
         next(); 
        } 
       })(); 
      } 
     } 
    } 
}; 
traverse(options, rootItemUrl, 0, function done(e, results) { 
    var text = ''; 
    for(var ii = 0; ii < results.length; ++ii) { 
     var itemInfo = results[ii]; 
     text += repeatChar(itemInfo.depth, '\t') + ('folder' === itemInfo.type ? '- (folder) ' : '') + 'depth: ' + itemInfo.depth + ' ' + itemInfo.name;    
    } 
    console.log(text); 
    console.log("End"); 
});