简体   繁体   English

返回promise时,我在此递归函数中做错了什么

[英]What am I doing wrong in this recursive function, when returning promise

I need to get the initial timestamps of all znodes in the zookeeper . 我需要获取zookeeper中所有znodes的初始timestamps I am using the getChildren method of node-zookeeper-client to do so. 我正在使用node-zookeeper-client的getChildren方法。 I am calling my getInitialTimeStamp recursively to traverse along the path. 我递归地调用我的getInitialTimeStamp以沿着路径遍历。 My function looks something like this 我的功能看起来像这样

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);
                });
        });
    });
}

it is being called like this 它被这样称呼

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

The problem is I can not get my .then() part to run. 问题是我无法运行我的.then()部分。 I know this is related to returning promise but I do not know what is being done wrong here. 我知道这与兑现诺言有关,但我不知道这里做错了什么。 Consider my lack of knowledge in promises and async programming and provide me with a solution. 考虑一下我对Promise和async编程缺乏知识,并为我提供了解决方案。

there are two things wrong .... if children is not empty, you never resolve ... and your children.map may as well be a forEach the way you're using it 有两件事是错误的....如果子代不为空,则您永远无法解决...而您的children.map也可能是forEach的使用方式

So, firstly, you want to resolve something if children has a length, and sescondly, you only want to do so once ALL the getInitialTimeStamp of the children is finished, by use of Promise.all 因此,首先,如果孩子有一个长度,您想解决一些问题;其次,您只想使用Promise.all完成孩子的所有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};  
                // 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);
        });
    });
}

Although that can be cleaned up a bit 虽然可以清理一点

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))));
        });
    });
}

but still no error checking is done ... ie test if error is truthy 但是仍然没有进行错误检查...即测试error是否真实

I would suggest this type of implementation that promisifies at a lower level by promisifying client.getChildren() . 我建议通过实现client.getChildren()来实现较低级别的实现。 That makes it a lot easier to write all your logic using promises and avoids common pitfalls of JaramandaX's implementation such as completely missing error handling and error propagation. 这使使用Promise编写所有逻辑变得容易得多,并且避免了JaramandaX实现的常见陷阱,例如完全丢失了错误处理和错误传播。

Since promises only resolve to a single value, when promisifying something that passes multiple values to its callback, you have to shoehorn each of the values into an object and resolve with that object. 由于promise只解析为一个值,因此当承诺将多个值传递给其回调的内容时,您必须将每个值塞入一个对象中并使用该对象进行解析。

Also, your implementation seems to be modifying some timeStamp global or higher scope variable which seems less than desirable. 另外,您的实现似乎正在修改一些timeStamp全局或更高范围的变量,这似乎不太理想。 So, I've made it so you can optionally pass in an object to start with, but if you don't it will default to an empty object and, in either case, the function will return a promise that will resolve to the object filled with the desired properties, including a cnt property so you can more easily see how many are there. 因此,我这样做了,因此您可以选择传入一个对象作为开始,但是如果不这样做,它将默认为一个空对象,并且在两种情况下,该函数都会返回一个将解析为该对象的promise填充了所需的属性,包括cnt属性,因此您可以更轻松地查看其中有多少。

getInitialTimeStamp() returns a promise that resolves to an object that contains your desired path properties. 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;
        });
    });
}

Usage: 用法:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM