为什么我的递归Javascript函数与Promises失败

时间:2015-06-03 22:30:43

标签: javascript recursion promise

我有JSON对象,我需要清理以$开头的属性。所以给定的结构下面应该摆脱$aaa$bbb$ccc$eee

{
  $aaa: "$aaa",
  bbb: "bbb",
  $ccc: {
    $ccc2: "$ccc2",
    ccc2a: "ccc2a"
  },
  ddd: {
    $ddd: "$ddd2",
    ddd2a: "ddd2a"
  },
  $eee: "$eee",
  fff: "fff"
}

我还想让它以异步方式运行并使用Promises。我无法让这个工作起来。它无法清除$eee并且不确定我哪里出错了。以下是完整代码和plunker is here

function clean$(obj1) {
  var obj = obj1;
  return new Promise(function(res, rej) {
    setTimeout(function() {
      for (var i in obj) {
        if (obj.hasOwnProperty(i)) {
          if (i.match(/^\$/)) {
            console.log("delete this " + i);
            delete obj[i];
          } else if (typeof obj[i] === "object") return clean$(obj[i]);
        }
      }
      res();
    }, 1000);
  })
}

sample = {
  $aaa: "$aaa",
  bbb: "bbb",
  $ccc: {
    $ccc2: "$ccc2",
    ccc2a: "ccc2a"
  },
  ddd: {
    $ddd: "$ddd2",
    ddd2a: "ddd2a"
  },
  $eee: "$eee",
  fff: "fff"
}

clean$(sample).then(function(res) {
  console.log("why it never gets here???");
})

2 个答案:

答案 0 :(得分:3)

问题在于这一行:

} else if (typeof obj[i] === "object") return clean$(obj[i]);

一旦它吸引了一个递归的对象,就会返回该递归调用的结果。但是,因为它在那时返回,所以它不会完成对当前级别元素的迭代。

在您的示例中,代码会递归以清除ddd并返回结果,因此不会继续清除$eee

有各种方法来解决这个问题。一种方法是建立一个返回的承诺列表,通过递归调用来清理,只有在它们全部解决后才返回。

答案 1 :(得分:1)

正如@knolleary所说,当你拨打$clean而不是继续时,你的内部超时功能正在返回。

此时,您的外部封闭已经返回了一个承诺。这个承诺只是等待调用res的东西,但这个调用永远不会发生。

初始调用正等待这个承诺解决,所以它可以写日志消息“为什么它永远不会到达这里???”。

您必须确保在所有情况下都调用resolve方法。此外,必须等待$clean的内部呼叫才能解决。

这是一个有效的解决方案:

function clean$(obj1) {
  var obj = obj1;
  return new Promise(function(res, rej) {
    setTimeout(function() {
      var promisesToWaitFor = [];
      for (var i in obj) {
        if (obj.hasOwnProperty(i)) {
          if (i.match(/^\$/)) {
            console.log("delete this " + i);
            delete obj[i];
          } else if (typeof obj[i] === "object") {
            promisesToWaitFor.push(clean$(obj[i]));
          }
        }
      };
      Promise.all(promisesToWaitFor).then(res);
    }, 1000);
  })
}

Plunkr Fork...