15

在我的 Parse Cloude 代码中,我需要运行几个连续的查询,每个查询都使用“find()”。

例子:

var promise = firstQuery.get(objectId).then(function(result1){
            return secondQuery.find();
        }).then(function(result2){
            return thirdQuery.find();
        }).then(function(result3) {

             // here I want to use "result1", "result2" and "result3"
        });

问题是:如何在最后的“then”语句中访问“result1”和“result2”,而不将它们分配给在父作用域中声明的变量。

我为什么要问这个问题:如果你嵌套了一堆你在循环中创建的 Promise 以使它们并行执行,那么你不能使用父作用域技巧(想象一下围绕上述语句的 for 循环,其中所有的 Promise 都是放入一个数组,然后使用“Parse.Promise.when”进行评估。它们都将同时开始修改父范围变量。)

我可以创建某种承诺对象,我可以在其中返回以下内容:

Parse.promise({result:result1,findResult:secondQuery.find()};

所以我可以通过执行从“result2”参数中获取值

result2.result 

result2.findResult

我希望我说清楚。这不是很容易解释。

4

3 回答 3

25

您可以使用闭包来执行此操作,而无需任何额外的对象或包装。

var promise = firstQuery.get(objectId).then(function(result1){
    return secondQuery.find()
    .then(function(result2) {
        return thirdQuery.find()
        .then(function(result3) {
            //can use result1, result2, result3 here
        });
    });
});

这种“嵌套”语法在功能上与您的“链接”语法相同。


根据评论编辑

如果你的 Promise 链足够长和复杂,以至于这种嵌套语法变得笨拙,那么逻辑可能足够复杂,值得抽象到它自己的函数中。

function complexQuery(objectId) {
    var results = {};
    return firstQuery.get(objectId).then(function(result1) {
        results.result1 = result1;
        return secondQuery.find();
    })
    .then(function(result2) {
        results.result2 = result2;
        return thirdQuery.find();
    })
    .then(function(result3) {
        results.result3 = result3;
        return results;
    });
}

complexQuery(objectId)
.then(function (results) {
    //can use results.result1, results.result2, results.result3
});

就个人而言,我认为这比使用.bind.

于 2014-08-12T00:24:24.880 回答
13

您不能使用父范围技巧

好吧,由于其他两个答案都这样做,所以让我提出一个不这样做的解决方案。您可以传递已解决的承诺。这还具有没有嵌套或闭包的额外好处。

这是基于 promise 已经是值的代理的概念,因此您实际上不必创建一个长链:

var firstObject = firstQuery.get(objectId);
var secondObject = firstObject.then(secondQuery.find.bind(secondQuery));
var thirdObject = secondObject.then(thirdQuery.find.bind(thirdQuery));
Promise.all(firstObject, secondObject, thirdObject).then(function(r1, r2, r3){
   // here you can use "r1", "r2" and "r3"
});

在标准的 Promise 中,这看起来与解析代码不同:

Promise.all([firstObject, secondObject, thirdObject]).then(function(){
   var r1 = arguments[0], r2 = arguments[1], r3 = arguments[2]; 
   // here you can use "r1", "r2" and "r3"
});

使用 bluebird,您可以使用.spread快捷方式.bind或实际上下文。如果你绝对必须创建一个链,你可以通过使用 Promise.all 返回多个 Promise 来传递上下文,但我相信这种方法更可取。

于 2014-08-12T06:58:39.263 回答
1

如果你想保持你的扁平链接语法而不是嵌套,你可以使用父作用域中的一个对象来共享:

var shared = {};
var promise = firstQuery.get(objectId).then(function(result1){
    // save results to shared object
    shared.result1 = result1;
    return secondQuery.find();
}).then(function(result2){
    shared.result2 = result2;
    return thirdQuery.find();
}).then(function(result3) {
    // here I want to use "result1", "result2" and "result3"
    // just use shared.result1, shared.result2
});
于 2014-08-12T02:09:55.900 回答