2013-09-19 2 views
7

Я пытаюсь использовать рекурсивные вызовы для получения данных из redis, остановки и возврата, когда члены возвращают null.Понимание обещаний в node.js для рекурсивной функции

Так мои данные добавлены как это:

SADD parents.<name> <parent1> <parent2> 
SADD parents.<parent1> <grandparent1> <grandparent2> 
... 

И окончательные данные должны выглядеть следующим образом:

[ 
{ 
    label: <name>, 
    parents: [ 
     { label: <parent1>, 
      parents: [ {label: <grandparent1>}, {label: <grandparent2> }] }, 
     { label: <parent2> } 
    ] 
} 
] 

Вот код, я баловаться с (вроде слепленный из различных источников), но я понятия не имею, что я делаю. Не уверен, что этот код даже полезен, я мог бы быть в стороне от трека.

var redis = require('node-redis'); 
var r_client = redis.createClient(); 
var Q = require('q'); 


function getFromRedis(nodeName){ 
     var ret = Q.defer(); 
     r_client.smembers('parents.' + nodeName,function(err,val){ 
       if (err) ret.reject(err); 
       else { 
         var constructedObject={}; //this is our returned object 
         var dependents=[]; 
         if (val) 
         { 
           for (var k in val){ //iterate the keys in val 
             constructedObject.name = val[k]; 

             dependents.push(getFromRedis(val[k]) 
             .then(function(subVal){ 
               constructedObject[k]=subVal; 
               return ret.promise; 
             }) 
             ); 
           } 
         } 
         else { return [] } 

       } 
       Q.all(dependents) 
       .then(function(){ret.resolve(constructedObject);},ret.reject.bind(ret)); 

     }); 
       return ret; 
} 

getFromRedis('greg', function(out) {console.log('Final output: ' + JSON.stringify(out))}); 

Я могу посмотреть на примеры и посмотреть, теоретически, как это должно работать, но я не могу получить мой взгляд вокруг, как он должен работать с реализацией д. Любая помощь будет принята с благодарностью.

+0

ли вы ранее имели обратный вызов на основе решения? – Bergi

+0

Нет. Я попробовал, но это было намного сложнее. –

ответ

3
  • Старайтесь быть такими же чистыми, как вы можете, работая с обещаниями. Избегайте функций, которые имеют побочные эффекты, т. Е. Манипулируют любыми переменными за пределами их собственной области.
  • Избегайте передачи обратных вызовов к функциям. Передавайте их только обещающим методам. Вы делаете это как с r_client.smembers() и при вызове вашего метода getFromRedis

Я вижу только один конкретную ошибку, которая будет держать ваш скрипт из работы:

return []; 

не имеет никакого эффекта от обратного вызова. Таким образом, ret никогда не будет разрешен в этом случае. Вы бы сделали ret.resolve([]); return;, если вообще. Тем не менее, есть лучшие решения, которые позволят вам снова использовать return.

Чтобы перестроить свой сценарий, есть две точки:

  • Используйте Q.nfcall helper function (и тому подобное), чтобы избежать работы с API-интерфейсов обратного вызова стиля напрямую. Используйте then, чтобы преобразовать его результат, затем - синхронно возвращая листья деревьев или обещание для вычислений, получающих потоки.
  • Сначала используйте Q.all, а затем преобразуйте его результат. Не добавляйте обработчик к каждому dependent, но получите весь результат и создайте construct за один шаг.

function getFromRedis(nodeName){ 
    return Q.ninvoke(r_client, "smembers", 'parents.' + nodeName).then(function(val) { 
     // this is our returned object 
     var constructedObject = {label: nodeName}; 
     if (val) { 
      var dependents = val.map(function(par) { 
       // get a promise for the next level 
       return getFromRedis(nodeName+"."+par.toString()); 
      }); 
      return Q.all(dependents).then(function(dependentResults) { 
       constructedObject.parents = dependentResults; 
       return constructedObject; 
      }); 
     } else { 
      return constructedObject; // without parents 
     } 
    }); 
} 

getFromRedis('greg').done(function(out) { 
    console.log('Final output: ' + JSON.stringify(out)); 
}); 
+0

Настолько более кратким. Все это имеет смысл, когда я вижу, что он работает так. По какой-то причине, когда я запускаю его из командной строки, он никогда не возвращает какой-либо вывод? Это похоже на то, что он застрял в петле. –

+0

О, я пропустил .done() в вызове. Дай мне попробовать снова. –

+0

Добавьте несколько журналов, чтобы узнать, что вы делаете с val, возможно, на самом деле. Я не знаю, что redis хорошо, возможно, что я правильно не построил запросы из значений - см. Часть кода [который я только что редактировал] (http://stackoverflow.com/posts/18905566/revisions) , вам может потребоваться адаптировать его. – Bergi

Смежные вопросы