将 $.Deferred() 与嵌套的 $.each 语句一起使用
Using $.Deferred() with nested $.each statements
我正在使用 SharePoint 进行 JSOM 调用。在检索到所有数据之前,我需要获得结果而不是继续前进。我已经尝试了很多示例(none 足够完整,足以让我了解如何使用嵌套的 $.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);
};
首先,等待 jQuery 中的多个承诺是用 $.when()
完成的。
$.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
});
接下来,我们需要将callback-based executeQueryAsync()
转换为promise-based 函数。通常,promisification 遵循以下方案:
function somethingPromise(args) {
var result = $.Deferred();
somethingAsync(/* onSuccess */ result.resolve, /* onError */ result.reject);
return result.promise();
}
这需要 onSuccess 和 onError 处理程序接收数据作为参数。 executeQueryAsync
不是这种情况 - 它直接修改 items
。但是,我们仍然想用 items
解决承诺,因此我们需要明确地这样做。
让我们将其应用到 SP.ClientContext
原型 right-away 上 re-use。
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();
};
接下来我们应该设置一个助手,将那些笨重的东西 collections 变成可用的东西。
function arrayFromCollection(coll) {
var arr = [], e = coll.getEnumerator();
while (e.moveNext()) arr.push(e.get_current());
return arr;
}
完成所有这些后,我们可以提取一个函数,该函数采用标题和 returns 项目数组的承诺。
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
将是项目数组的数组。
我正在使用 SharePoint 进行 JSOM 调用。在检索到所有数据之前,我需要获得结果而不是继续前进。我已经尝试了很多示例(none 足够完整,足以让我了解如何使用嵌套的 $.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);
};
首先,等待 jQuery 中的多个承诺是用 $.when()
完成的。
$.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
});
接下来,我们需要将callback-based executeQueryAsync()
转换为promise-based 函数。通常,promisification 遵循以下方案:
function somethingPromise(args) {
var result = $.Deferred();
somethingAsync(/* onSuccess */ result.resolve, /* onError */ result.reject);
return result.promise();
}
这需要 onSuccess 和 onError 处理程序接收数据作为参数。 executeQueryAsync
不是这种情况 - 它直接修改 items
。但是,我们仍然想用 items
解决承诺,因此我们需要明确地这样做。
让我们将其应用到 SP.ClientContext
原型 right-away 上 re-use。
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();
};
接下来我们应该设置一个助手,将那些笨重的东西 collections 变成可用的东西。
function arrayFromCollection(coll) {
var arr = [], e = coll.getEnumerator();
while (e.moveNext()) arr.push(e.get_current());
return arr;
}
完成所有这些后,我们可以提取一个函数,该函数采用标题和 returns 项目数组的承诺。
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
将是项目数组的数组。