【问题标题】:How to recursively build a list using a callback and iterating through the children?如何使用回调递归地构建列表并遍历子项?
【发布时间】:2017-06-06 14:59:36
【问题描述】:

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

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

应附加通过附加到整个文件中创建的“最终”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);
    });
}

我知道

buildItem(item, function(subHtml){
    html += subHtml;
})

不应该工作,因为 javascript 是异步的。我只是不确定如何从递归函数返回?如果我要做类似的事情

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

您将获得重复值,因为您将拥有起始值并且它是子值,但由于您还调用它,您将获得起始值之外的子值。所以它看起来像

1
     a
     b
     c
     d
     e
a
b
c
d
e

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

getTotalCost 是另一个回调函数,意义不大,我无意中删除了该行,但我只需要数据库中的 totalCost。

function getTotalCost(item, callback) {
    $.ajax({
        dataType: "json",
        url: "/retrieveData.do?item=" + item.email,
        success: function(data) {
            var totalCost = 0;
            for (var i = 0; i < data.length; i++) {
                totalCost += parseFloat(data[i].cost);
            }
            callback(totalCost);
        }
    });
}

【问题讨论】:

    标签: javascript jquery asynchronous recursion html-lists


    【解决方案1】:

    您可以使用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

    【讨论】:

    • 我想我可以,但是我正在使用 IE11,并且被转译的代码看起来并不容易维护。我希望有一个解决方案可以建立在我已有的基础上。
    • @CHom 你什么意思?您无需维护已转译的代码——它仅适用于浏览器。
    • 我正在开发以在大型网站上使用,作为该项目的开发人员之一,我认为我不想对特定代码的完成方式做出如此大的改变部分。不过,如果我不在这个项目中,我想使用它。
    • @CHom 然后你可以使用series function of async library
    • 这是否意味着除了使用另一个库之外没有可行的解决方案?只是想知道。
    【解决方案2】:

    如果您通过同步执行器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

    【讨论】:

      猜你喜欢
      • 2021-10-05
      • 2019-08-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-30
      • 2014-03-01
      • 2020-01-24
      • 2013-07-13
      相关资源
      最近更新 更多