链接承诺递归

时间:2012-09-05 23:12:32

标签: javascript windows-8 winjs

我正在开发一个简单的Windows 8应用,我需要从网站上获取一组数据。我正在使用WinJS.xhr()来检索此数据,该数据返回Promise。然后我将一个回调传递给这个Promise的.then()方法,该方法为我的回调提供异步调用的返回值。 .then()方法返回另一个Promise,为其提供我的回调返回的值。这种查询的基本结构如下:

WinJS.xhr({ url: "http://www.example.com/" }).then(
    function callback( result_from_xhr )
    {
        //do stuff
        return some_value;
    }).then(
    function secondcallback( some_value )
    {
        //do stuff
    });

然而,在我的情况下,我可能需要根据第一个查询返回的数据进行额外的数据查询,并且可能需要更多查询,具体取决于THAT数据...等等,递归。

我需要一种方法对其进行编码,以便在所有递归完成之前不执行最终的.then(),类似于:

function recurse() {
    return WinJS.xhr({ url: "http://www.example.com/" }).then(
        function callback( result_from_xhr )
        {
            if( result_from_xhr == something )
            {
               recurse();
            }
        });
}

recurse().then(
function final()
{
    //finishing code
});

问题是,当然,只要第一级递归完成,就会调用完成代码。我需要一些方法来在回调中嵌套新的promise和旧的promise。

我希望我的问题很清楚,我真的不确定如何解释它,坦率地说,异步递归代码的想法会让我头疼。

4 个答案:

答案 0 :(得分:13)

我在这里要做的是创建一个全新的独立承诺,您可以手动完成,并从recurse()函数返回。然后,当你知道自己完成了异步工作时,就完成了这个承诺。

当你有一套已知的承诺时,Promise.join会起作用 - 你需要在调用join之前提供整个promise数组。如果我遵循原始问题,您将拥有可变数量的承诺,并且可能会更多地作为异步工作的一部分弹出。在这种情况下,加入不是正确的工具。

那么,这是什么样的?像这样:

function doSomethingAsync() {
  return new WinJS.Promise(function (resolve, reject) {
    function recurse() {
      WinJS.xhr({ url: "http://www.example.com/" })
        .then(function onResult(result_from_xhr) {
          if (result_from_xhr === something) {
            recurse();
          } else {
            // Done with processing, trigger the final promise
            resolve(whateverValue);
          },
          function onError(err) {
            // Fail everything if one of the requests fails, may not be
            // the right thing depending on your requirements
            reject(err);
          });
    }
    // Kick off the async work
    recurse();
  });
}

doSomethingAsync().then(
function final()
{
    //finishing code
});

我重新安排了递归发生的位置,这样我们就不会每次都重新创建一个新的promise,因此嵌套的recurse()函数而不是它在外层。

答案 1 :(得分:5)

在制作我自己的Windows 8应用程序时,我可能以不同的方式解决了这个问题(我认为这是同样的问题)。

我遇到此问题的原因是,默认情况下,对表的查询将进行分页,并且一次只返回50个结果,因此我创建了一个模式以获取前50个,然后是下一个50,等等,直到回复结果少于50,然后解决承诺。

此代码不是真正的代码,只是为了说明:

function getAllRows() {
    return new WinJS.Promise(function(resolve, reject){

        var rows = [];

        var recursivelyGetRows = function(skipRows) {
            table.skip(skipRows).read()
                .then(function(results){
                    rows = rows.concat(results);

                    if (results.length < 50) {
                        resolve(rows);
                    } else {
                        recursivelyGetRows(skipRows + 50);
                    }
                })
        }

        recursivelyGetRows(0);

    });
}

所以getAllRows()返回一个只有在我们得到一个少于50个结果的结果后才能解析的promise(这表明它是最后一页)。

根据您的使用情况,您可能也想在其中抛出错误处理程序。

如果不清楚,'table'是一个移动服务表。

答案 2 :(得分:1)

您需要使用Promise.join()。done()模式。将一个Promises数组传递给join(),在您的情况下,它将是xhr调用的集合。当所有xhr Promise都完成时,join()将只调用done()。您将获得一系列传递给done()的结果,然后您可以迭代并使用新的Promise.join()。done()调用再次启动。当使用这种方法时,要离开的是,如果其中一个Promise传递给join()失败,整个操作将被视为错误条件。

抱歉,我现在没时间尝试为您存档代码。如果我有机会,我会稍后尝试。但是你应该能够将它插入到递归函数中并使其工作。

答案 3 :(得分:0)

好吧,我解决了我的问题;我的递归函数误解了数据,因此从未停止递归。感谢您的帮助,我一定会看那些截屏视频,因为我还没有完全掌握Promise链接结构。