如何使用回调递归构建列表并遍历子项?

时间:2017-06-06 14:59:37

标签: javascript jquery asynchronous recursion html-lists

我不确定如何构建此列表(这是一个字符串),然后作为一个完整的字符串返回。 我已经完成了上一期的工作,但我觉得这个问题真的让我很烦恼。 buildItem()应该遍历item,然后递归地构建一个列表,同时从另一个回调中获取totalCost。我知道它是异步工​​作的......

+------+------+------+------------+--------+---------+----------+------------+
| Year | Code | Unit |     CA     | Unit_P |  CA_P   | Unit_PPP |   CA_PPP   |
+------+------+------+------------+--------+---------+----------+------------+
| 2017 |  280 |    6 | 1789027.00 |     16 | 4800000 |        8 | 2385027.00 |
| 2017 |  281 |    0 |       0.00 |      2 |  500000 |        0 |       0.00 |
| 2017 |  282 |    0 |       0.00 |      1 |  250000 |        0 |       0.00 |
+------+------+------+------------+--------+---------+----------+------------+

应该附加最终的'通过在整个文件中附加而创建的html字符串。

buildItem(data, function(html){
    $('#nestable ol').append(html);
});

我知道

function buildItem(item, callback) {
    getTotalCost(item, function(totalCost) {
        var html = "<li class='dd-item' data-id='" + item.id + "' data-email='" + item.email + "' data-title='" + item.corporateTitle + "' data-name='" + item.firstName + " " + item.lastName + "' id='" + item.id + "'>";
        if (item.children && item.children.length > 0) {
            html += "<ol class='dd-list'>";
            $.each(item.children, function (index, sub) {
                buildItem(item, function(subHtml){
                    html += subHtml;
                })
            })
            html += "</ol>";
        }
        html += "</li>";
        callback(html);
    });
}
由于javascript是异步的,所以

不应该工作。我不确定如何从递归函数返回?如果我要做像

这样的事情
buildItem(item, function(subHtml){
    html += subHtml;
})

您将获得重复的价值,因为您已经拥有了起始价值及其子女,但既然您还要回复它,那么您将把孩子带到起始值。所以它看起来像

buildItem(item, function(subHtml){
    callback(subHtml);
})

那么接近解决方案的最佳方式是什么?我正在考虑制作另一个函数,假设是一个返回html的buildChild(sub),但异步的相同问题将会出现,返回将是未定义的。我已经阅读了一些可以使用回调来处理异步值的线程,但我不确定如何使用递归来处理异步值。

getTotalCost是另一个不应该意味着很多的回调函数,我偶然删除了这行,但我只需要数据库中的totalCost。

1
     a
     b
     c
     d
     e
a
b
c
d
e

2 个答案:

答案 0 :(得分:0)

您可以使用promisesasync functions简化此操作:

async function getTotalCost(item) {
  const data = await Promise.resolve($.ajax({
    dataType: "json",
    url: "/retrieveData.do?item=" + item.email
  }));
  return data.reduce((acc, next) => acc + next.cost, 0);
}

async function buildItem(item) {
  const totalCost = await getTotalCost(item);
  let html = `<li class="dd-item" data-id="${item.id}" data-email="${item.email}" data-title="${item.corporateTitle}" data-name="${item.firstName} ${item.lastName}" id="${item.id}">`;
  if (item.children && item.children.length > 0) {
    html += '<ol class="dd-list">';
    for (const childItem of item.children) {
      html += await buildItem(childItem);
    }
    html += "</ol>";
  }
  html += "</li>";
  return html;
}

很遗憾,所有浏览器都不支持异步功能,因此您必须使用Babel来转换代码。

我还添加了一些新的ES6功能:arrow functionsconsttemplate literals

答案 1 :(得分:0)

如果您通过同步执行程序nsynjs执行代码,则可以将慢速ajax请求与逻辑和递归混合在一起。

步骤1.将您的逻辑编写为同步,并将其置于函数中:

function process(item) {
    function getTotalCost(item) {
        var data = jQueryGetJSON(nsynjsCtx, "/retrieveData.do?item=" + item.email).data;
        var totalCost = 0;
        for (var i = 0; i < data.length; i++) {
            totalCost += parseFloat(data[i].cost);
        }
        return totalCost;
    };

    function buildItem(item) {
        const totalCost = getTotalCost(item);
        var html = "<li class='dd-item' data-id='" + item.id + "' data-email='" + item.email + "' data-title='" + item.corporateTitle + "' data-name='" + item.firstName + " " + item.lastName + "' id='" + item.id + "'>";

        if (item.children && item.children.length > 0) {
            html += '<ol class="dd-list">';
            for (var i=0; i<item.children.length; i++)
                html += buildItem(item.children[i]);
            html += "</ol>";
        }
        html += "</li>";
        return html;
    };

    return buildItem(item);
};

第2步:通过nsynjs:

运行它
nsynjs.run(process,{},item,function (itemHTML) {
    console.log("all done",itemHTML);
});

请在此处查看更多示例:https://github.com/amaksr/nsynjs/tree/master/examples