将$ .Deferred()与嵌套$ .each语句一起使用

时间:2018-08-02 15:16:03

标签: sharepoint jquery-deferred

我正在使用SharePoint进行JSOM调用。我需要获取结果,并且在获取所有数据之前不要继续前进。我已经尝试了很多示例(没有一个完整的示例足以使我了解如何使用嵌套的$ .each循环语句来解决我的问题。我似乎已经接近了,但是从来没有任何正常工作。

我已经编辑了我的实际代码(减去了从另一个页面传入的前3个变量),以合并Tomalak的工作,以便我们可以更好地弄清楚。当前,结果是空对象。试图弄清楚我做错了什么。

[编辑于2018年8月6日] 终于让它工作了。我发现提供的代码只有两个小问题:-)。我会尝试加粗它们。

var fya = [2008,2009]; //Fiscal Year Array which we use to know what lists to look at
var assignedRecords = []; //Global Reusable Variable
var assignedCourses = ['Math','Science','Reading']; //There might not be records who are associated with a particular course in each list. Wee need to pull the student records (assignedRecords) assoiciated with the above in 2008 and 2009.

SP.ClientContext.prototype.executeQueryPromise = function (items) {
    var result = $.Deferred();
    this.load(items);
    this.executeQueryAsync(function (sender, args) { result.resolve(items) }, 
        function (sender, args) { result.reject(args) });
    return result.promise();
};

移动'var arr = [];'在arrayFromCollection之外 在同一函数中将'var'添加到e变量

var arr = [];
function arrayFromCollection(coll) {
    var e = coll.getEnumerator();
    while (e.moveNext()) arr.push(e.get_current());
    return arr;
};

function queryListPromise(title, course) {
    var list = hostWeb.get_lists().getByTitle(title);
    var camlQuery = new SP.CamlQuery();
    camlQuery.set_viewXml('<View><Query><Where>'
        + '<Eq><FieldRef Name="Course"/><Value Type="Text">' + course + '</Value></Eq>'
        + '</Where></Query></View>');
    return context.executeQueryPromise(list.getItems(camlQuery)).then(arrayFromCollection);
};

function GetAssignedApplications() {
    assignedRecords = []; //Need to start empty
    var myCourses = assignedCourses;

    $.each(myCourses, function (i, myCoursesItem) {
        var courseName = myCoursesItem.get_lookupValue();

将“ $ .forEach”更改为“ $ .each”

        $.each(fya, function (n, fyaItem) {
            var listTitle = "FY" + String(fyaItem).substring(2); //FY18 & FY19 are the names of the actual lists.
            assignedRecords.push(queryListPromise(listTitle, courseName));
        });
    });

    $.when(assignedRecords).then(function (results) {
        return Array.prototype.concat.apply([], results);
    }).then(function (items) {
        items.forEach(function (item) {
            var a = item; //item is empty and this actually runs before arrayFromCollection and it returns duplicate records (4) when there is only 2.
        });
    }).fail(onError);
};

1 个答案:

答案 0 :(得分:0)

因此首先,$.when()完成了在jQuery中等待多个promise。

$.when(p1, p2, p3).then(function (results) {
    // results is an array of length 3
});

为了通过可变的参数计数实现此目的,我们使用Function#apply

var promises = [p1, p2, p3]; // could be be of any length now

$.when.apply($, promises).then(function () {
    var results = [].slice.call(arguments);
    // results is an array of the same length as promises
});

为了使其可重用,我们将其称为$.whenAll

$.whenAll = function (promises) {
    return $.when.apply($, promises).then(function () {
        return [].slice.call(arguments);
    });
};

现在我们可以做到:

$.whenAll([p1, p2, p3]).then(function (results) {
    // results is an array of length 3
});

接下来,我们需要将基于回调的executeQueryAsync()转换为基于Promise的函数。通常,承诺遵循以下方案:

function somethingPromise(args) {
    var result = $.Deferred();
    somethingAsync(/* onSuccess */ result.resolve, /* onError */ result.reject);
    return result.promise();
}

这期望onSuccess和onError处理程序将数据作为参数接收。 executeQueryAsync并非如此-它直接修改items。但是,我们仍然想用items来解决诺言,因此我们需要明确地做到这一点。

让我们立即将其拍打到SP.ClientContext原型上以重新使用。

SP.ClientContext.prototype.executeQueryPromise = function (items) {
    var result = $.Deferred();
    this.load(items);
    this.executeQueryAsync(
        function (sender, args) { result.resolve(items); },
        function (sender, args) { result.reject(args); }
    );
    return result.promise();
};

接下来,我们应该建立一个助手,将那些笨拙的收藏集变成有用的东西。

function arrayFromCollection(coll) {
    var arr = [], e = coll.getEnumerator();
    while (e.moveNext()) arr.push(e.get_current());
    return arr;
}

完成所有操作后,我们可以提取一个函数,该函数带有标题并为项目数组返回promise。

function queryListPromise(title) {
    var list = web.get_lists().getByTitle(title);
    var q = new SP.CamlQuery();
    //...
    return ctx.executeQueryPromise(list.getItems(q)).then(arrayFromCollection);
}

最后,由于您想要一个简单的项目列表,因此我们应该从一个简单的查询列表开始:

function GetNextFunction() {
    var queries = [];

    // build flat list of queries
    $.each(arr1, function(i, arr1Item) {
        $.each(arr2, function(n, arr2Item) {
            queries.push(queryListPromise(arr2Item));
        });
    });

    // wait on all queries
    $.whenAll(queries).then(function (results) {
        // flatten incoming array of arrays
        return Array.prototype.concat.apply([], results);
    }).then(function (items) {
        // items contains all items from all queries
        items.forEach(function (item) { /* ... */ });
    }).fail(onError);
}

这里queries变成了承诺的平面数组,每个承诺都将解析为一组项目。因此,results将是一组由项目组成的数组。