在循环和嵌套函数中使用 Promises
Using Promises with Loops and Nested Functions
我正在尝试将承诺与循环和其中一些循环中的嵌套函数一起使用。我有一系列函数应该从 REST 调用中带回 SharePoint 列表项 - 一旦这些函数执行完毕,就会调用另一个函数,该函数使用带回的数据。
由于有多个列表,随后每个列表中有多个列表项,我使用了一个 while 循环来进行每个 REST 调用,并从那里将数据(列表项)放入对象中。这些对象被放入一个数组中,这就是第二个函数用来继续的对象。
我无法收到 promise 的回复。我在考虑将多个承诺推送到一个数组,然后最终使用 Promise.all
查看是否在使用 then
之前一切都已解决。问题是所有的承诺都保持 pending
因为我没有正确返回 resolve
。请看下面。
function onQuerySuccess(sender, args) {
var itemEnumerator = items.getEnumerator();
while (itemEnumerator.moveNext()) {
var promise = new Promise(function (resolve, reject) {
var item = itemEnumerator.get_current();
item = item.get_item('URL');
var itemUrl = item.get_description();
getRequestItemsFromList(itemUrl);
});
promises.push(promise); // all promises are present, but their status is pending
}
console.log(promises);
Promise.all(promises).then(function (val) {
console.log(val);
execFuncs(); // function to execute once all the above are done
}).catch(function (response) {
console.log(response);
});
}
因为涉及的函数比较多,所以执行顺序是这样的:
getRequestItemsFromList //gets url for each list
execCrossDomainRequest (on success call) // makes REST call to get list and its items
cleanData // trims data and puts it in objects
最后一个是我想调用 Promise.resolve()
的地方,因为那是该行的结尾。
不管怎样,这都行不通。我检查了其他线程,但我试图在不使用任何库的情况下执行此操作。提前致谢。
编辑:
完整相关代码:
var promises = [];
window.requests = [];
function getRequestLists() {
var requestsLists = hostWeb.get_lists().getByTitle('Name'); // sharepoint list with all the request list urls.
context.load(requestsLists);
var camlQuery = new SP.CamlQuery();
camlQuery.set_viewXml('<View></View>');
var items = requestsLists.getItems(camlQuery);
context.load(items, 'Include(URL)');
context.executeQueryAsync(onQuerySuccess, onQueryFail);
function onQuerySuccess(sender, args) {
var itemEnumerator = items.getEnumerator();
while (itemEnumerator.moveNext()) {
var promise = new Promise(function (resolve, reject) {
var item = itemEnumerator.get_current();
item = item.get_item('URL');
var itemUrl = item.get_description();
getRequestItemsFromList(itemUrl);
});
promises.push(promise);
}
console.log(promises);
Promise.all(promises).then(function (val) {
console.log(val);
execFuncs(); // not shown here
}).catch(function (response) {
console.log(response);
});
}
function onQueryFail(sender, args) {
alert("Request to retrieve list URL items has failed. " + args.get_message());
}
}
function getRequestItemsFromList(url) {
var lastPos = getSubstringIndex(url, "/", 4);
var webUrl = url.substring(0, lastPos); // truncates list url to parse out web url
var absListPos = getSubstringIndex(url, "AllItems.aspx", 1);
var absListUrl = url.substring(0, absListPos); // truncates the AllItems.aspx at the end of the list url
var relListPos = getSubstringIndex(absListUrl, "/", 3);
var relListUrl = absListUrl.substring(relListPos, absListUrl.length); // gets the list's relative url
var listName = "List Name";
console.log(webUrl);
execCrossDomainRequest(webUrl, listName, absListUrl);
}
function execCrossDomainRequest(webUrl, listName, absListUrl) {
var executor = new SP.RequestExecutor(appWebUrl);
executor.executeAsync({ // to collect the list description
url: appWebUrl + "/_api/SP.AppContextSite(@target)/web/lists/getbytitle(@name)?" +
"@target='" + webUrl + "'&@name='" + listName + "'" +
"&$select=Description",
method: "GET",
headers: { "Accept": "application/json; odata=verbose" },
success: onCallSuccess,
error: onCallFail
});
function onCallSuccess(data) {
var json = JSON.parse(data.body);
var description = json.d.Description;
executor.executeAsync({ // to collect the list item information
url: appWebUrl + "/_api/SP.AppContextSite(@target)/web/lists/getbytitle(@name)/items?" +
"@target='" + webUrl + "'&@name='" + listName + "'" +
"&$top=500&$select=*," +
"Assigned_x0020_To/Title" +
"&$expand=Assigned_x0020_To/Id",
method: "GET",
headers: { "Accept": "application/json; odata=verbose" },
success: onItemsCallSuccess,
error: onItemsCallFail
});
function onItemsCallSuccess(data) {
var itemsJson = JSON.parse(data.body);
var results = itemsJson.d.results;
cleanData(results, description, absListUrl);
}
function onItemsCallFail(data, errorCode, errorMessage) {
console.log("Could not make list items cross domain call. " + errorMessage);
}
}
function onCallFail(data, errorCode, errorMessage) {
console.log("Could not make list cross domain call. " + errorMessage);
}
}
function cleanData(results, listDescription, absListUrl) {
if (!results.length) {
return;
}
for (var i = 0; i < results.length; i++) {
var client = listDescription;
var id = results[i].ID;
...
}
var request = new Request(client, id, path, title, status, estimated, assignedTo, priority, description, response);
window.requests.push(request);
}
return Promise.resolve();
}
在我看来你的 promises 数组没有定义:do var promises = [];在你的 while 循环之前。
当你像这样使用 promise 构造函数时:
var promise = new Promise(function (resolve, reject) {
这意味着您正在调用 resolve
and/or reject
来完成承诺。
但你永远不会这样做,让创建的承诺对象永远处于挂起状态。
我正在尝试将承诺与循环和其中一些循环中的嵌套函数一起使用。我有一系列函数应该从 REST 调用中带回 SharePoint 列表项 - 一旦这些函数执行完毕,就会调用另一个函数,该函数使用带回的数据。
由于有多个列表,随后每个列表中有多个列表项,我使用了一个 while 循环来进行每个 REST 调用,并从那里将数据(列表项)放入对象中。这些对象被放入一个数组中,这就是第二个函数用来继续的对象。
我无法收到 promise 的回复。我在考虑将多个承诺推送到一个数组,然后最终使用 Promise.all
查看是否在使用 then
之前一切都已解决。问题是所有的承诺都保持 pending
因为我没有正确返回 resolve
。请看下面。
function onQuerySuccess(sender, args) {
var itemEnumerator = items.getEnumerator();
while (itemEnumerator.moveNext()) {
var promise = new Promise(function (resolve, reject) {
var item = itemEnumerator.get_current();
item = item.get_item('URL');
var itemUrl = item.get_description();
getRequestItemsFromList(itemUrl);
});
promises.push(promise); // all promises are present, but their status is pending
}
console.log(promises);
Promise.all(promises).then(function (val) {
console.log(val);
execFuncs(); // function to execute once all the above are done
}).catch(function (response) {
console.log(response);
});
}
因为涉及的函数比较多,所以执行顺序是这样的:
getRequestItemsFromList //gets url for each list
execCrossDomainRequest (on success call) // makes REST call to get list and its items
cleanData // trims data and puts it in objects
最后一个是我想调用 Promise.resolve()
的地方,因为那是该行的结尾。
不管怎样,这都行不通。我检查了其他线程,但我试图在不使用任何库的情况下执行此操作。提前致谢。
编辑:
完整相关代码:
var promises = [];
window.requests = [];
function getRequestLists() {
var requestsLists = hostWeb.get_lists().getByTitle('Name'); // sharepoint list with all the request list urls.
context.load(requestsLists);
var camlQuery = new SP.CamlQuery();
camlQuery.set_viewXml('<View></View>');
var items = requestsLists.getItems(camlQuery);
context.load(items, 'Include(URL)');
context.executeQueryAsync(onQuerySuccess, onQueryFail);
function onQuerySuccess(sender, args) {
var itemEnumerator = items.getEnumerator();
while (itemEnumerator.moveNext()) {
var promise = new Promise(function (resolve, reject) {
var item = itemEnumerator.get_current();
item = item.get_item('URL');
var itemUrl = item.get_description();
getRequestItemsFromList(itemUrl);
});
promises.push(promise);
}
console.log(promises);
Promise.all(promises).then(function (val) {
console.log(val);
execFuncs(); // not shown here
}).catch(function (response) {
console.log(response);
});
}
function onQueryFail(sender, args) {
alert("Request to retrieve list URL items has failed. " + args.get_message());
}
}
function getRequestItemsFromList(url) {
var lastPos = getSubstringIndex(url, "/", 4);
var webUrl = url.substring(0, lastPos); // truncates list url to parse out web url
var absListPos = getSubstringIndex(url, "AllItems.aspx", 1);
var absListUrl = url.substring(0, absListPos); // truncates the AllItems.aspx at the end of the list url
var relListPos = getSubstringIndex(absListUrl, "/", 3);
var relListUrl = absListUrl.substring(relListPos, absListUrl.length); // gets the list's relative url
var listName = "List Name";
console.log(webUrl);
execCrossDomainRequest(webUrl, listName, absListUrl);
}
function execCrossDomainRequest(webUrl, listName, absListUrl) {
var executor = new SP.RequestExecutor(appWebUrl);
executor.executeAsync({ // to collect the list description
url: appWebUrl + "/_api/SP.AppContextSite(@target)/web/lists/getbytitle(@name)?" +
"@target='" + webUrl + "'&@name='" + listName + "'" +
"&$select=Description",
method: "GET",
headers: { "Accept": "application/json; odata=verbose" },
success: onCallSuccess,
error: onCallFail
});
function onCallSuccess(data) {
var json = JSON.parse(data.body);
var description = json.d.Description;
executor.executeAsync({ // to collect the list item information
url: appWebUrl + "/_api/SP.AppContextSite(@target)/web/lists/getbytitle(@name)/items?" +
"@target='" + webUrl + "'&@name='" + listName + "'" +
"&$top=500&$select=*," +
"Assigned_x0020_To/Title" +
"&$expand=Assigned_x0020_To/Id",
method: "GET",
headers: { "Accept": "application/json; odata=verbose" },
success: onItemsCallSuccess,
error: onItemsCallFail
});
function onItemsCallSuccess(data) {
var itemsJson = JSON.parse(data.body);
var results = itemsJson.d.results;
cleanData(results, description, absListUrl);
}
function onItemsCallFail(data, errorCode, errorMessage) {
console.log("Could not make list items cross domain call. " + errorMessage);
}
}
function onCallFail(data, errorCode, errorMessage) {
console.log("Could not make list cross domain call. " + errorMessage);
}
}
function cleanData(results, listDescription, absListUrl) {
if (!results.length) {
return;
}
for (var i = 0; i < results.length; i++) {
var client = listDescription;
var id = results[i].ID;
...
}
var request = new Request(client, id, path, title, status, estimated, assignedTo, priority, description, response);
window.requests.push(request);
}
return Promise.resolve();
}
在我看来你的 promises 数组没有定义:do var promises = [];在你的 while 循环之前。
当你像这样使用 promise 构造函数时:
var promise = new Promise(function (resolve, reject) {
这意味着您正在调用 resolve
and/or reject
来完成承诺。
但你永远不会这样做,让创建的承诺对象永远处于挂起状态。