如何正确编写递归jquery promise

时间:2015-12-18 18:47:34

标签: javascript jquery promise

请原谅我,如果我重复一个已经非常被问到的问题,但到目前为止我所看到的一切似乎都没有给我递归,或者没有映射到我们正在做的事情和主题承诺和延期对我来说似乎非常复杂。

我有一个"主题树"随着用户扩展节点而异步构建。本主题使用API​​端点构建,该端点在单击主题树节点上的(+)按钮时返回节点的子节点。

当用户点击按钮时,我尝试使用如下所示的方法递归加载主题树元素:

function getAssociatedTopics(){
    $.get('/topics/curriculum-associations', {guids: [...]})
    .then(function(data){

        //Process the topic information here
        var topicId = /* some processing */;

        //Get ancestors of each topic returned
        $.get('/topics/getAncestors', {of: topicId})
        .then(function(data){

            //Process the topic information here
            var topicId = /* some processing */;

            //Get ancestors of each topic returned
            //Rinse repeat as long as we find children of each topic found


        });

    }).then(function(){

        //Expand the nodes
        //Select the nodes

    });
}

所以这应该是它应该是什么样子但是我都忘记阅读文档以确保我的东西以正确的顺序执行...我们现在对这个结构的大问题是我的节点所有以并发方式加载然后擦除所选节点,随时打开和关闭节点,选择结束时非常混乱。

我不想深入解释承诺,也不想要一个完整的解决方案,而是一个大致的想法如何实现这一点。

1 个答案:

答案 0 :(得分:1)

首先,获取所需内容的复杂性应该在服务器而不是客户端上处理。从客户端发出数百个HTTP请求是一个等待发生的性能灾难。

现在你要怎么做,有两个重要的事实:

  • 使用返回值来承诺工作。 $.get会返回价值的承诺 - 这就是为什么then可以将其取消,但您也可以将其退回到外面。
  • 如果您从then处理程序返回一个承诺,则从then本身返回的承诺将等待内部承诺首先解决。

以下是一个说明这两点的例子:

$.get("/api").then(function(data) {
    return $.get("/api2/" + data.id);
}).then(function(data2) {
    // because of point #1, we get the data of the inner call here.
});

现在,针对您的实际问题:

function getAssociatedTopics(guids) {
    // note the `return` here so it can be chained from outside 
    return $.get('/topics/curriculum-associations', {guids: guids})
    .then(function(data){
        var topicId = someProcessing(data);
        // note we return here. I assume this get returns guids. 
        return $.get('/topics/getAncestors', {of: topicId})
    }).then(function (guids) { // this anonymous function can be inlined
        if(guids.length === 0) return; // stop condition
        return getAssociatedTopics(guids); // note the recursive call, remember point #2.
    });
}
getAssociatedTopics(initial).then(function(){
    // all done
});

如果需要所有调用的结果,可以将其链接起来,或者可以在最后一个之前推送到闭包变量数组,并在all done处理程序中访问它。