2017-01-10 107 views
0

我需要得到zookeeper中所有znodes的初始timestamps。我正在使用node-zookeeper-client的getChildren方法来执行此操作。我递归地调用我的getInitialTimeStamp来遍历路径。我 功能看起来像这样我在做这个递归函数时做错了什么,当返回promise时

function getInitialTimeStamp(client,path){ 
    return new Promise((resolve,reject) => { 
     client.getChildren(
      path, 
      function(error,children,stats){ 
       //if children empty, return 
       if (typeof children === 'undefined' || children.length <= 0) {resolve();} 

       timeStamp[path]= {ctime: stats.ctime, mtime: stats.mtime}; 
       children.map(child => { 
        getInitialTimeStamp(client,path+'/'+child); 
       }); 
     }); 
    }); 
} 

它被称为像这样

getInitialTimeStamp(client,path) 
    .then(() => { 
     console.log(timeStamp); 
     console.log("finished"); 
}); 

问题是我不能让我的.then()部分运行。我知道这与回诺有关,但我不知道这里做错了什么。考虑我对承诺和async编程缺乏认识,并为我提供解决方案。

回答

1

有两件事情错了....如果孩子不为空,你永远不解决......和你children.map不妨是一个foreach你使用它

这样的方式,首先,你要解决的东西,如果孩子有一个长度,sescondly,你只是想这样做,一旦所有的孩子的getInitialTimeStamp完成后,通过使用Promise.all

function getInitialTimeStamp(client,path){ 
    return new Promise((resolve,reject) => { 
     client.getChildren(
      path, 
      function(error,children,stats){ 
       //if children empty, return 
       if (typeof children === 'undefined' || children.length <= 0) { 
        resolve(); 
       } 
       timeStamp[path]= {ctime: stats.ctime, mtime: stats.mtime}; 
       // use promise.all to wait for all child timestamps 
       Promise.all(children.map(child => getInitialTimeStamp(client,path+'/'+child))) 
       // and then resolve this path 
       .then(resolve); 
     }); 
    }); 
} 

的虽然可以清理有点

function getInitialTimeStamp(client, path) { 
    return new Promise((resolve, reject) => { 
     client.getChildren(path, (error, children, stats) => { 
      timeStamp[path]= {ctime: stats.ctime, mtime: stats.mtime}; 
      resolve(Promise.all((children||[]).map(child => getInitialTimeStamp(client, path + '/' + child)))); 
     }); 
    }); 
} 

,但仍然没有进行错误检查......即测试,如果error是truthy

+0

这是不是可以,如果'client.getChildren()'直接promisified简单得多。正如现在这个答案,它缺少错误处理,如果你提出更低的级别,然后使用promise来编程所有的逻辑,那么错误处理几乎是免费的。 – jfriend00

+0

是的,它当然会,那么 –

+0

你怎么promisify client.getChildren()? – Prasanna

1

我建议这种类型的实现,在一个较低的水平由promisifying client.getChildren() promisifies。这使得使用promise来编写所有的逻辑变得容易很多,并且避免了JaramandaX实现的常见缺陷,如完全缺少错误处理和错误传播。

由于promise只能解析为单个值,所以在promisifying一些将多个值传递给其回调的东西时,您必须将每个值锁定到一个对象中并使用该对象进行解析。

此外,您的实施似乎正在修改一些timeStamp全局或更高范围变量,这似乎不太理想。所以,我已经做到了,所以你可以选择传递一个对象来开始,但是如果你不这样做,它将默认为一个空对象,并且在任何一种情况下,该函数都会返回一个将解析为该对象的承诺填充所需的属性,包括cnt属性,以便您可以更轻松地查看有多少个属性。

getInitialTimeStamp()返回一个承诺,该承诺解析为包含所需路径属性的对象。

// make promisified version that resolves to an object with properties on it 
// Depending upon the situation, you might add this to the prototype rather than 
// to an instance 
client.getChildrenP = function(path) { 
    return new Promise((resolve, reject) => { 
     this.getChildren(path, (error, children, stats) => { 
      if (error) return reject(error); 
      resolve({children, stats}); 
     }); 
    }); 
} 

// Returns a promise that resolves to a timeStamp object 
// You can optionally pass in an object to be modified or that will default 
// to an empty object. In either case, the returned promise resolves to 
// the finished object. 
function getInitialTimeStamp(client, path, resultsObj){ 
    let obj = resultsObj || {cnt: 0}; 
    obj.cnt = obj.cnt || 0; 
    return client.getChildrenP(path).then(results => { 
     if (typeof results.children === 'undefined' || children.length <= 0) { 
      // return results so far 
      return obj; 
     } 
     ++obj.cnt; 
     obj[path]= {ctime: results.stats.ctime, mtime: results.stats.mtime}; 
     return Promise.all(children.map(child => { 
      getInitialTimeStamp(client,path+'/'+child, obj); 
     })).then(results => { 
      return obj; 
     }); 
    }); 
} 

用法:

getInitialTimeStamp(client, somePath).then(resultsObj => { 
    // process resultsObj here 
}).catch(err => { 
    // process error here 
}); 
+0

我到了那里jfriend00,没有想到'resultObj'那样,真好!我所关心的唯一事情是在'client.getChildrenP'调用'client.getChildren' - 看起来硬编码混乱,如果你有一个以上的客户对象(不管它是什么!) –

+0

@JaromandaX - 是啊,我刚换' client.getChildren()'到'this.getChildren()'。这就是我的意思。 – jfriend00

+0

原代码,'OBJ [路径] = {的ctime:results.stats.ctime,修改时间:results.stats.mtime};如果在你的代码是还没有孩子'被设置甚至,我认为这是跳过如果目前的结果没有孩子 - 因为回报 - 我认为你需要移动你的儿童逻辑检查 –

相关问题