返回承诺时,我在这个递归函数中做错了什么
What am I doing wrong in this recursive function, when returning promise
我需要获取 zookeeper
中所有 znodes
的初始 timestamps
。我正在使用 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()
部分转换为 运行。我知道这与返回承诺有关,但我不知道这里做错了什么。考虑到我在 promises 和 async
编程方面缺乏知识,并为我提供解决方案。
有两处错误....如果children不为空,你永远不会解决...而且你的children.map也可能是你使用它的方式的forEach
所以,首先,如果 children 有长度,你想解决一些问题,其次,你只想在 children 的所有 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
是否为真
我建议通过承诺 client.getChildren()
在较低级别承诺这种类型的实现。这使得使用 promises 编写所有逻辑变得容易得多,并避免了 JaramandaX 实现的常见缺陷,例如完全缺少错误处理和错误传播。
由于 promises 仅解析为单个值,因此当 promisify 将多个值传递给其回调时,您必须将每个值硬塞到一个对象中并使用该对象进行解析。
此外,您的实施似乎正在修改某些 timeStamp
全局或更高范围的变量,这似乎不太理想。所以,我已经这样做了,所以你可以选择传入一个对象作为开始,但如果你不这样做,它将默认为一个空对象,并且在任何一种情况下,该函数都会 return 一个将解析为填充有所需属性的对象,包括 cnt
属性 这样您就可以更轻松地查看其中有多少。
getInitialTimeStamp()
return是一个解析为包含所需路径属性的对象的承诺。
// 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
});
我需要获取 zookeeper
中所有 znodes
的初始 timestamps
。我正在使用 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()
部分转换为 运行。我知道这与返回承诺有关,但我不知道这里做错了什么。考虑到我在 promises 和 async
编程方面缺乏知识,并为我提供解决方案。
有两处错误....如果children不为空,你永远不会解决...而且你的children.map也可能是你使用它的方式的forEach
所以,首先,如果 children 有长度,你想解决一些问题,其次,你只想在 children 的所有 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
是否为真
我建议通过承诺 client.getChildren()
在较低级别承诺这种类型的实现。这使得使用 promises 编写所有逻辑变得容易得多,并避免了 JaramandaX 实现的常见缺陷,例如完全缺少错误处理和错误传播。
由于 promises 仅解析为单个值,因此当 promisify 将多个值传递给其回调时,您必须将每个值硬塞到一个对象中并使用该对象进行解析。
此外,您的实施似乎正在修改某些 timeStamp
全局或更高范围的变量,这似乎不太理想。所以,我已经这样做了,所以你可以选择传入一个对象作为开始,但如果你不这样做,它将默认为一个空对象,并且在任何一种情况下,该函数都会 return 一个将解析为填充有所需属性的对象,包括 cnt
属性 这样您就可以更轻松地查看其中有多少。
getInitialTimeStamp()
return是一个解析为包含所需路径属性的对象的承诺。
// 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
});