我有一个函数,可以在其中循环执行并执行一小组查询,这些查询使用Breeze.js返回数据块。该代码的每个部分都有效,但只有一行(我尝试在其中将查询结果添加到数组中)。我尝试了各种方法,但似乎无法弄清楚为什么它不起作用。

function doStuff(sourceArray, outputObservable, errorObservable) {
    var arr = [];

    _.each(sourceArray, function (sourceItem) {
        return breeze.EntityQuery
            .from("SomeTable")
            .using(manager).execute()
            .then(getSucceeded)
            .fail(getFailed);

        function getSucceeded(data) {
            _.each(data.results, function (item) {
                console.log(item); //This works
                arr.push(item);  //This doesn't work
            });
        }

        function getFailed(error) {
            errorObservable("Error retrieving data: " + error.message);
        }
    });

    outputObservable(arr);
}


这会将每个查询的所有结果输出到控制台,但不会将结果输出到数组。但是,如果将第二行更改为var arr = [ 1, 2, 3, 4, 5 ];,则这些值将反映在outputObservable中。

编辑:下面是完整的解决方案。

function doStuff(sourceArray, outputObservable, errorObservable) {
    var promises = [];
    var arr = [];

    //Create an array of promises
    _.forEach(sourceArray, function (item) {
        promises.push(getDataFromServer(item.val1, item.val2));
    });

    //Wait for all promises to resolve, then set output
    Q.all(promises).then(function () {
        outputObservable(arr);
    });

    function getDataFromServer(filter1, filter2) {
        var p1 = breeze.Predicate.create("field1", "==", filter1);
        var p2 = breeze.Predicate.create("field2", "==", filter2);

        return breeze.EntityQuery
            .from("SomeTable")
            .where(p1.and(p2))
            .using(manager).execute()
            .then(getSucceeded)
            .fail(getFailed);

        function getSucceeded(data) {
            _.each(data.results, function (item) {
                arr.push(item);
            });
        }

        function getFailed(error) {
            errorObservable("Error retrieving processes: " + error.message);
        }
    }
}

最佳答案

啊,异步的经典陷阱。 getSucceeded被异步调用,这意味着您将其作为回调传递给EntityQuery,后者随后将调用它。

_.each(sourceArray, ...)返回时,所有查询将开始但仍在运行。这些都还没有完成,您的回调也没有被调用。因此,当您将arr传递给outputObservable时,它仍保持不变。您应该能够在调试器中注意到这一点:在console.log之前添加outputObservable,您会发现它将在任何console.log(item)调用之前被调用。

您只想在所有异步查询完成后调用outputObservable。我对Breeze或underscore.js不太熟悉,但是您需要将execute()返回的诺言合并为新的诺言。当所有的承诺都解决后,这个新的承诺就会得到解决,因此您应该在其上附加一个then回调并调用outputObservable

关于javascript - 为什么不能在此特定函数中添加到数组中?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/18522504/

10-11 12:38