我需要获取timestamps
中所有znodes
的初始zookeeper
。我正在使用node-zookeeper-client的getChildren
方法来执行此操作。我以递归方式调用getInitialTimeStamp
来遍历路径。我的
功能看起来像这样
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
编程缺乏了解,并为我提供了解决方案。
答案 0 :(得分:1)
有两件事是错的......如果孩子不是空的,你永远不会解决......而你的孩子。地图也可能是你每次使用它的方式
所以,首先,如果孩子有一个长度,你想要解决一些事情,其次,你只想在所有孩子的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
是否真实
答案 1 :(得分:1)
我建议通过宣传client.getChildren()
在较低级别实现这种类型的实施。这使得使用promises编写所有逻辑变得容易得多,并避免了JaramandaX实现的常见缺陷,例如完全缺少错误处理和错误传播。
由于promises只解析为单个值,因此在将多个值传递给其回调的内容时,必须将每个值变为对象并使用该对象解析。
此外,您的实现似乎正在修改一些timeStamp
全局或更高范围的变量,这似乎不太理想。所以,我已经做到了,所以你可以选择传入一个对象开始,但如果你不这样做,它将默认为一个空对象,在任何一种情况下,该函数都会返回一个promise解析填充了所需属性的对象,包括cnt
属性,以便您可以更轻松地查看有多少属性。
getInitialTimeStamp()
返回一个promise,该promise将解析为包含所需路径属性的对象。
// 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
});