承诺递归

时间:2016-12-10 20:31:52

标签: node.js es6-promise mongoose-populate

我在users中有database个列表:

let users = []; // Please check the full list at the end of this post

这是我的findUsers函数:(这个函数看起来像是从数据库中搜索。但我只是用硬编码数据编写简单函数)

function findUsers(user) {
  return new Promise(function (resolve) {
    resolve(user.users);
  });
}

我希望得到所有以userId开头的用户:

const walkUsers = (user, list) => {
  let usrLst = user.users;
  list = list || [];
  usrLst.forEach((usr) => {
    if (usr.users.length > 0) {
      list = walkUsers(usr, list);
    }
    list.push(usr);
  });
  return list;
};

此函数返回正确的结果。

[
  { id: '009', name: 'User 9', users: [] },
  { id: '011', name: 'User 11', users: [] },
  { id: '010', name: 'User 10', users: [ [Object] ] },
  { id: '004', name: 'User 4', users: [ [Object], [Object] ] },
  { id: '003', name: 'User 3', users: [ [Object] ] },
  { id: '007', name: 'User 7', users: [] },
  { id: '002', name: 'User 2', users: [ [Object], [Object] ] },
  { id: '008', name: 'User 8', users: [] },
  { id: '005', name: 'User 5', users: [ [Object] ] },
  { id: '006', name: 'User 6', users: [] }
]

但这不是我的预期。我想从数据库(Mongoose)中获取数据

const walkUsers = (user, list) => {
  return findUsers(user)
    .then((usrLst) => {
      list = list || [];
      usrLst.forEach((usr) => {
        if (usr.users.length > 0) {
          walkUsers(usr, list).then((rtnLst) => {
            console.log("rtnLst");
            console.log(rtnLst);
            return rtnLst;
          });
        }
        list.push(usr);
      });

      return list;
    });
};

此功能缺少用户009010011

[
  { id: '002', name: 'User 2', users: [ [Object], [Object] ] },
  { id: '005', name: 'User 5', users: [ [Object] ] },
  { id: '006', name: 'User 6', users: [] },
  { id: '003', name: 'User 3', users: [ [Object] ] },
  { id: '007', name: 'User 7', users: [] },
  { id: '008', name: 'User 8', users: [] },
  { id: '004', name: 'User 4', users: [ [Object], [Object] ] }
]

我无法弄清楚我错了什么。你能帮我看一下吗?

检查users数据:

let users = [
  {
    id: '001',
    name: 'User 1',
    users: [
      {
        id: '002',
        name: 'User 2',
        users: [
          {
            id: '003',
            name: 'User 3',
            users: [
              {
                id: '004',
                name: 'User 4',
                users: [
                  {
                    id: '009',
                    name: 'User 9',
                    users: []
                  },
                  {
                    id: '010',
                    name: 'User 10',
                    users: [
                      {
                        id: '011',
                        name: 'User 11',
                        users: []
                      },
                    ]
                  },
                ]
              }
            ]
          },
          {
            id: '007',
            name: 'User 7',
            users: []
          }
        ]
      },
      {
        id: '005',
        name: 'User 5',
        users: [
          {
            id: '008',
            name: 'User 8',
            users: []
          }
        ]
      },
      {
        id: '006',
        name: 'User 6',
        users: []
      },
    ]
  },
];

1 个答案:

答案 0 :(得分:3)

您需要进行以下更改:

  1. usrLst.forEach()循环中,累积您获得的承诺列表,然后使用Promise.all(),以便了解它们何时完成。现在,您没有跟踪何时完成对walkUsers()的调用,这取决于时间,您可能会丢失或遗漏某些结果。
  2. 然后,您需要从.then()处理程序返回该主承诺,以便将其链接到findUsers()正在返回的父walkUsers()承诺。
  3. 这可能是这样的:

    const walkUsers = (user, list) => {
      return findUsers(user)
        .then((usrLst) => {
          list = list || [];
          var promises = [];
          usrLst.forEach((usr) => {
            if (usr.users.length > 0) {
              promises.push(walkUsers(usr, list));
            }
            list.push(usr);
          });
    
          return Promise.all(promises).then(function() {
              // make the list be the resolved value from this promise
              return list;
          });
        });
    };
    

    请记住,只要在.then()处理程序中进行异步操作,就应该始终从.then()处理程序返回一个promise,以便将内部异步操作链接到父操作并且在完成所有嵌套异步操作之前,不会告知调用者已完成任务。如果没有,那个内部异步操作就变成了一个孤立的异步操作,它在它自己的时间运行,并且它上面没有任何东西等待它或与它协调,以及调用者是否看到它的结果将是一个运气计时和你的代码如何工作(这会产生不确定的结果)。