带有promises的JavaScript递归 - 执行错误的顺序

时间:2016-05-20 15:45:58

标签: javascript asynchronous recursion

构建一种在画布导航中为Web应用程序创建标记的方法。我正在对另一个返回父菜单节点的子节点的服务进行异步回调(参见下面的代码):

function GenerateMarkup(Terms, n) {
    var termsEnum = Terms.getEnumerator();
    var html = "<ul>";

    // Process top level terms
    while (termsEnum.moveNext()) {
        var currentTerm = termsEnum.get_current();        

        html += "<li>"

        if (currentTerm.get_termsCount() > 0) {
            var childcall = function() {
                var deferred = $.Deferred();

                html += "<a href=\"#\">" + currentTerm.get_name() + "<br><span>" + currentTerm.get_description() + "</span></a>";
                SPTermStore.GetTermsFromTermSet(currentTerm).then(function(termSet) {
                    if (typeof termSet !== undefined) {
                        deferred.resolve(GenerateMarkup(termSet, n++));
                    }
                    else
                        deferred.reject("something bad happened");
                });
                return deferred.promise();
            };

           $.when(childcall()).done(function(markup) {
                html += markup;
            });
        } // end if
        else
            html += "<a href=\"#\">" + currentTerm.get_name() + "</a>";

        html += "</li>"
    } // end while

    html += "</ul>";
    console.log("GenerateMarkup (" + n + "): " + html);
    return html;
} // end function

问题是标记生成的顺序不正确;在正常的同步中,GenerateMarkup的递归调用将完成,但在这种情况下,我试图等待返回的promise(即对GenerateMarkup的调用完成),所以我可以追加html。这个想法是在迭代过程中,顶级节点将处理其子节点等。

如果我查看console.log输出,这就是我得到的;问题是下面列出的第一个标记是返回页面的内容,而不是下面的组合。

GenerateMarkup (0): <ul><li><a href="#">About<br><span>Our Company</span></a></li><li><a href="#">Portfolio<br><span>Our Properties</span></a></li><li><a href="#">Corporate Responsibility<br><span>Our Committment</span></a></li></ul>
GenerateMarkup (0): <ul><li><a href="#">Careers</a></li><li><a href="#">Core Values</a></li><li><a href="#">Governance</a></li><li><a href="#">History</a></li></ul>
GenerateMarkup (1): <ul><li><a href="#">Core Market Strategy</a></li><li><a href="#">Our Properties</a></li></ul>
GenerateMarkup (2): <ul><li><a href="#">Community Involvement</a></li><li><a href="#">CSR Report</a></li><li><a href="#">Diversity</a></li><li><a href="#">Sustainability</a></li></ul>

任何帮助都将不胜感激。

2 个答案:

答案 0 :(得分:1)

Promise是异步的,所以他们不能保证按照他们承诺的顺序返回。

如果排序很重要,请考虑将promises链接起来,以便它们按照您期望的顺序执行。 Promise.then can be chained.

答案 1 :(得分:0)

一种可能性是遍历termsenumerator,并将它们加载到延迟数组中。然后应用$ when。见下面的示例:

 var deferreds = [];
 for (var i = 0; i<termsenumerator; i++) {              
      deferreds.push(Grab data you want and push it into this array);             
 }

//Now that we have all the results... (deferred), process these.
        $.when.apply($, deferreds).done(function () {

            var resultdata = [];

            for (var i = 0; i < arguments.length; i++) {
                var daydata = arguments[i][2];                   
                applymarkupWData(resultdata.responseJSON.d,i);


            };

        });